1、信号
信号是Linux系统种用于进程间通讯或者操作的一种机制。这个信号可以在任何时候发送给一个进程,无需制定该进程的状态。
如果说这个进程么有在执行的状态,内核可以先把这个信号保存下来。当进程恢复运行再把这个信号发送给它。信号也是可以
设置成阻塞的状态,这个信号的传递就会延迟,当阻塞的状态取消之后,才可以被进程接收到。
信号他是软件层面对中断机制的一种模拟,是一个异步通讯的过程。
信号的来源:
1)硬件来源,例如我们按下了ctrl+c,就产生了一个中断的信号。
2)软件的来源,使用系统调用,或者通过命令发送信号,常见的发送信号的系统函数:kill
如何处理我们收到的信号:
1)执行默认的操作,Linux系统对每一种信号都有默认的操作方式。
2)捕获这个信号,定义信号的处理函数,当接收到这个信号,我们怎么处理?你想怎么处理就怎么处理。
3)忽略这个信号,就是不对这个信号做处理。
有两个信号是应用程序无法捕获和忽略的信号,SIGKILL SEGSTOP.
系统中的信号定义在这个地方:/usr/include/i386-linux-gnu/bits/signum.h
/* Signals. */
#define SIGHUP 1 /* Hangup (POSIX). 控制中断挂起的时候 */
#define SIGINT 2 /* Interrupt (ANSI).从键盘上接受到的中断信号,ctrl+c */
#define SIGQUIT 3 /* Quit (POSIX). ctrl+d */
#define SIGILL 4 /* Illegal instruction (ANSI). 非法指令 */
#define SIGTRAP 5 /* Trace trap (POSIX). 调试程序,跟踪 */
#define SIGABRT 6 /* Abort (ANSI). 放弃 */
#define SIGIOT 6 /* IOT trap (4.2 BSD). */
#define SIGBUS 7 /* BUS error (4.2 BSD). 总线错误 */
#define SIGFPE 8 /* Floating-point exception (ANSI). 浮点运算错误 */
#define SIGKILL 9 /* Kill, unblockable (POSIX). 杀死一个进程,该信号不能被阻塞、处理或者忽略 */
#define SIGUSR1 10 /* User-defined signal 1 (POSIX) . */
#define SIGSEGV 11 /* Segmentation violation (ANSI). */
#define SIGUSR2 12 /* User-defined signal 2 (POSIX). 用户定义的信号 */
#define SIGPIPE 13 /* Broken pipe (POSIX). 管段出错 */
#define SIGALRM 14 /* Alarm clock (POSIX). 闹钟时间 */
#define SIGTERM 15 /* Termination (ANSI). 中止 */
#define SIGSTKFLT 16 /* Stack fault. 栈出错 */
#define SIGCLD SIGCHLD /* Same as SIGCHLD (System V). 子进程状态发送改变 */
#define SIGCHLD 17 /* Child status has changed (POSIX). 子进程的状态发生改变 ,当子进程退出的时候,
向父进程发送此信号,如果父进程正在运行wait函数,就会被唤醒,如果没有wait函数,父进
程就不会捕获这个信号,此时子进程就会变成僵尸进程 */
#define SIGCONT 18 /* Continue (POSIX). 继续运行信号 */
#define SIGSTOP 19 /* Stop, unblockable (POSIX). 停止信号 该信号不能被阻塞、处理或者忽略*/
#define SIGTSTP 20 /* Keyboard stop (POSIX). 键盘停止 */
#define SIGTTIN 21 /* Background read from tty (POSIX). 后台读取tty */
#define SIGTTOU 22 /* Background write to tty (POSIX). 后台写tty */
#define SIGURG 23 /* Urgent condition on socket (4.2 BSD). */
#define SIGXCPU 24 /* CPU limit exceeded (4.2 BSD). */
#define SIGXFSZ 25 /* File size limit exceeded (4.2 BSD). */
#define SIGVTALRM 26 /* Virtual alarm clock (4.2 BSD). */
#define SIGPROF 27 /* Profiling alarm clock (4.2 BSD). */
#define SIGWINCH 28 /* Window size change (4.3 BSD, Sun). 窗口大小发生改变 */
#define SIGPOLL SIGIO /* Pollable event occurred (System V). */
#define SIGIO 29 /* I/O now possible (4.2 BSD). */
#define SIGPWR 30 /* Power failure restart (System V). */
#define SIGSYS 31 /* Bad system call. */
2、信号的发送
通过系统提供的一些函数,可以发送一些信号:
kill ,发送一个SIGKILL给进程。
raise 发送信号给进程或者给自己
alarm 定时器的事件到,向进程发送一个SIGALRM
pause 没有捕获到信号之前一直是挂起
signal() 当捕获到某一种信号之后,绑定对应的处理函数,然后自定义去处理这个信号。
#include <signal.h>
sigset_t *set先定义信号的集合,
int sigemptyset(sigset_t *set); 清空该集合
int sigfillset(sigset_t *set); 初始化信号集合为所有信号
int sigaddset(sigset_t *set, int signum); 将指定的信号,加到对应的信号集合里面
int sigdelset(sigset_t *set, int signum); 把指定的信号从这个集合里面去掉
int sigismember(const sigset_t *set, int signum); 查询指定的信号,在不在这个集合里面。
以上函数,成功就返回0,失败返回-1,并且对应的错误码会被设置。
3、信号的处理
可以使用调用signal这个函数,将我们需要捕获的信号,和我们自定义的这个处理函数绑定起来,
当捕获到绑定的信号的时候处理函数就会被调用。
#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
4、信号的阻塞
当我们不想将收到的信号,立刻处理的时候,但是我们也不想把这个信号忽略掉,希望延时一段时间再去处理它,
这个时候,就需要用到信号的阻塞来处理。
#include <signal.h>
sigset_t *set先定义信号的集合,
int sigemptyset(sigset_t *set); 清空该集合
int sigfillset(sigset_t *set); 初始化信号集合为所有信号
int sigaddset(sigset_t *set, int signum); 将指定的信号,加到对应的信号集合里面
int sigdelset(sigset_t *set, int signum); 把指定的信号从这个集合里面去掉
int sigismember(const sigset_t *set, int signum); 查询指定的信号,在不在这个集合里面。
以上函数,成功就返回0,失败返回-1,并且对应的错误码会被设置。
将信号变成阻塞型的信号:
#include <signal.h>
int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
阻塞:SIG_BLOCK
不阻塞:SIG_UNBLOCK
例子:
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
void func_ctrl_c(int sig)
{
if(sig == SIGINT)
{
printf("Now you press ctrl+c\n");
}
if(sig == SIGQUIT)
{
printf("Now we get a signal SIGQUIT\n");
}
// signal(SIGINT,SIG_DFL); //当我们捕获到绑定的信号之后,也可以调用系统默认的方式去处理它。
}
int main()
{
int i;
sigset_t set;
signal(SIGINT,func_ctrl_c);
signal(SIGQUIT,func_ctrl_c);
if(sigemptyset(&set) < 0) //清空该集合
{
perror("sigemptyset error");
exit(-1);
}
if(sigaddset(&set,SIGINT) < 0) //将指定的信号加到对应的信号集合里面
{
perror("sigaddset fail");
exit(-1);
}
if(sigprocmask(SIG_BLOCK,&set,NULL) < 0)//将信号变成阻塞型的信号
{
perror("set block fail");
exit(-1);
}
for(i=0;i<3;i++)
{
printf("Now is block the signal\n");
sleep(3);
}
if(sigprocmask(SIG_UNBLOCK,&set,NULL) < 0)
{
perror("set block fail");
exit(-1);
}
return 0;
}