【摘要】信号是学习 linux 时必须要熟悉的一部分,没有了信号 Linux 系统就没办法正常的工作。而我们作为 Linux 程序员,也要用到信号来进行程序的运行,没有了信号,我们的工作将会变得一团糟。这几天,我把刚刚学的关于信号的知识点总结了一下,分享给大家,希望可以对大家有所帮助。
信号是 linux 系统为了响应某些状况而产生的事件。进程收到信号后应该采取相应的动作
kill -l
这个命令就可以查看所有的信号啦,现在信号已经增加到 65 个了,但是在这里我要提一下,从 33-64 这些信号一般不会采用,这是为了区分可靠信号和不可靠信号而新增加的 32 个信号。关于可靠信号和不可靠信号,我会在下面加以说明滴。
下面我把最常用到的信号给大家解释一下
#define SIGHUP 1 /* hangup */
#define SIGINT 2 /* interrupt */
#define SIGQUIT 3 /* quit */
#define SIGILL 4 /* illegal instruction (not reset when caught) */
#define SIGTRAP 5 /* trace trap (not reset when caught) */
#define SIGABRT 6 /* abort() */
#if (defined(_POSIX_C_SOURCE) && !defined(_DARWIN_C_SOURCE))
#define SIGPOLL 7 /* pollable event ([XSR] generated, not supported) */
#else /* (!_POSIX_C_SOURCE || _DARWIN_C_SOURCE) */
#define SIGIOT SIGABRT /* compatibility */
#define SIGEMT 7 /* EMT instruction */
#endif /* (!_POSIX_C_SOURCE || _DARWIN_C_SOURCE) */
#define SIGFPE 8 /* floating point exception */
#define SIGKILL 9 /* kill (cannot be caught or ignored) */
#define SIGBUS 10 /* bus error */
#define SIGSEGV 11 /* segmentation violation */
#define SIGSYS 12 /* bad argument to system call */
#define SIGPIPE 13 /* write on a pipe with no one to read it */
#define SIGALRM 14 /* alarm clock */
#define SIGTERM 15 /* software termination signal from kill */
#define SIGURG 16 /* urgent condition on IO channel */
#define SIGSTOP 17 /* sendable stop signal not from tty */
#define SIGTSTP 18 /* stop signal from tty */
#define SIGCONT 19 /* continue a stopped process */
#define SIGCHLD 20 /* to parent on child stop or exit */
#define SIGTTIN 21 /* to readers pgrp upon background tty read */
#define SIGTTOU 22 /* like TTIN for output if (tp->t_local<OSTOP) */
#if (!defined(_POSIX_C_SOURCE) || defined(_DARWIN_C_SOURCE))
#define SIGIO 23 /* input/output possible signal */
#endif
#define SIGXCPU 24 /* exceeded CPU time limit */
#define SIGXFSZ 25 /* exceeded file size limit */
#define SIGVTALRM 26 /* virtual time alarm */
#define SIGPROF 27 /* profiling time alarm */
#if (!defined(_POSIX_C_SOURCE) || defined(_DARWIN_C_SOURCE))
#define SIGWINCH 28 /* window size changes */
#define SIGINFO 29 /* information request */
#endif
#define SIGUSR1 30 /* user defined signal 1 */
#define SIGUSR2 31 /* user defined signal 2 */
信号量值 | 名称 | 发送方式 | 说明 |
---|---|---|---|
(2) | SIGINT | ctrl +c | 终止信号 |
(3) | SIGQUIT | ctrl + \ | 暂停信号,放入后台 |
(4) | SIGILL | 非法指令 | |
(5) | SIGTRAP | abort(3) | 进程异常终止 |
(7) | SIGBUS | (虚实关系建立) 总线错误(从写的位置到物理内存,操作系统没有将磁盘的开始位置到物理内存之间建立 联系 mmap(把虚拟内存和磁盘文件的关系映射起来,如果磁盘大小大于 0,就建立这种关系 | |
(9) | SIGKILL | kill - 9 pid | 杀死进程 |
(11) | SIGSEGV | 段错误 | |
(13) | SIGPIPE | 管道破裂 | |
(14) | SIGALRM | 闹钟 | |
(15) | SIGTERM | 缺省终止某个进程,终止掉 | |
(17) | SIGSTOP | 子进程死的时候会给父进程发送这个信号 | |
(19) | SIGCONT | 进程暂停 | |
(23) | SIGURG | 紧急数据 | |
(29) | SIGINFO | 异步 IO |
这个就要使用 man 手册自己去查找啦,有好多呢,记住常用的就可以啦
man 7 signal 在第七页,所以直接用 man 7
typedef void (\* sighandler_t) (int);
sighandler_t signal (int signum //要注册的信号
,sighandler_t handler); //信号执行函数 1.自己定义函数
2.SIG_IGN #define SIG_IGN (sighandler_t(1))把 1 强制转化为函数指针类型
3.SIG_DFL #define SIG_IGN (sighandler_t(0))把 0 强制转化为函数指针类型
返回错误 SIG_ERR
#define SIG_ERR
信号是异步事件,当信号到达时,保存当前的执行环境,转去执行信号处理函数,当信号处理函数完毕,恢复现场,继续执行
Linux 的信号继承自早期的 Unix 信号,Unix 信号的缺陷 1.信号处理函数执行完毕,信号恢复成默认处理方式(Linux 已经改进) 2.会出现信号丢失,信号不排队
1-31 都是不可靠的,会出现信号丢失现象
34-64 重新设计的一套信号集合
不会出现信号丢失,支持排队,信号处理函数执行完毕,不会恢复成缺省处理方式
实时信号 : 就是可靠信号
非实时信号:不可靠信号
kill -信号值 pid
int kill(int pid,int signum)
pid > 0 :发送给 pid 进程
pid = 0 :调用者所在进程组的任一进程
pid = -1: 有权发送的任何一个进程,除了 1
pid < -1 |pid|进程组所有的进程
用管道连接的进程, fork 创建的父子进程都属于同一个进程组
sleep 返回值 > 0 表示还剩多少秒没睡就被信号打断
raise( int signum )
kill(getpid() ,signum)
给进程组发信号
int killpg(int gid,int signum);
暂停进程,直到被信号打断
int pause( void )把当前进程变成就绪态,让出 CPU calling process
SIGALRM
int alarm(int sec)
当 sec 规定的时间到了,触发 SIGALRM 信号
如果 sec 是 0,表示清除信号
下面是两个 SIGALRM 信号的使用范例,希望通过这两个实例可以加深你们对于闹钟信号的理解啊
#include
#include
#include
#include
void handler(int s) //信号到来,则执行这个函数,输出超时
{
printf("超时\n");
exit(1);
}
int main()
{
char buf[100] = {};
printf("输入名字");
signal(SIGALRM, handler); //定义一个信号函数,当 SIGALRM 信号发过来时,执行 handler 函数
alarm(5); //设置五秒的时钟,五秒内如果没有执行输入操作就会发送信号
scanf("%s", buf);
alarm(0); //如果五秒内执行了操作,那就清空闹钟
printf("名字为:%s\n", buf);
for (;;) //验证闹钟时间已经清空
{
fflush(stdout);
printf(".");
sleep(1);
}
}
执行结果
代码如下
#include
#include
#include
#include
int count = 0; //初始化
int wrong = 0; //初始化
void handler(int s) //当闹钟信号发过来,执行这个函数,输出对错的个数
{
printf("time out \n");
printf("right = %d,wrong = %d\n ", count, wrong);
exit(1);
}
int main()
{
int i = 0;
signal(SIGALRM, handler); //定义信号函数接收信号
alarm(30); //设置闹钟时间为 30 秒
srand(getpid()); //用子进程 id 作为随机种子数
for (i = 0; i < 10; i++) //循环十次,输出随机数相加结果
{
int left = rand() % 10;
int right = rand() % 10;
printf("%d + %d=", left, right);
int ret;
while (getchar() != '\n')
; //清空输入缓冲区,防止异常输入使得程序崩溃
scanf("%d", &ret);
if (left + right == ret) //判断对错
{
count++;
}
else
{
wrong++;
}
}
printf("做完了\n");
printf("right =%d,wrong = %d \n", count, wrong);
}
程序结果如下
从这两个实例,我们已经可以知道时钟的简单用法啦,那么说了这么多,我觉得你们也可以自己上手去做一个以闹钟为中心的小程序啦。再另一篇博客里面我会讲一讲时钟的用法,希望可以帮助到你们哦。
注:我也是个初学者啦,如果哪里又纰漏之处,欢迎指正啊,也可以私信我,我很喜欢交流的。
作者:zb1593496558
来源:CSDN
原文:https://blog.csdn.net/zb1593496558/article/details/80280346
版权声明:本文为博主原创文章,转载请附上博文链接!