信号是进程间通信中一种简单而有效的机制,用于通知进程发生了某个事件。当某个进程产生一个信号时,它可以向其他进程发送信号,并触发接收进程的信号处理函数。信号机制可以用于进程之间的异步通信,比如在一个进程执行的过程中,另一个进程可以通过发送信号来中断或修改其执行行为。
信号是内核进程通知用户进程应该干什么了
信号是由操作系统或其他进程发送给目标进程的通知,可以表示某种事件的发生,如按下Ctrl+C键、子进程终止等。进程可以设置信号处理函数来对收到的信号做出响应,处理函数可以是用户自定义的函数。
信号是用整数表示的,不同的信号有不同的整数值。例如,SIGINT代表终止进程的信号,其整数值为2。Linux系统中有许多不同的信号,每个信号都有特定的含义和用途。
信号名 | 编号 | 信号名 | 编号 | 信号名 | 编号 |
---|---|---|---|---|---|
SIGHUP | 1 | SIGRTMIN | 34 | SIGRTMAX-9 | 55 |
SIGINT | 2 | SIGRTMIN+1 | 35 | SIGRTMAX-8 | 56 |
SIGQUIT | 3 | SIGRTMIN+2 | 36 | SIGRTMAX-7 | 57 |
SIGILL | 4 | SIGRTMIN+3 | 37 | SIGRTMAX-6 | 58 |
SIGTRAP | 5 | SIGRTMIN+4 | 38 | SIGRTMAX-5 | 59 |
SIGABRT | 6 | SIGRTMIN+5 | 39 | SIGRTMAX-4 | 60 |
SIGBUS | 7 | SIGRTMIN+6 | 40 | SIGRTMAX-3 | 61 |
SIGFPE | 8 | SIGRTMIN+7 | 41 | SIGRTMAX-2 | 62 |
SIGKILL | 9 | SIGRTMIN+8 | 42 | SIGRTMAX-1 | 63 |
SIGUSR1 | 10 | SIGRTMIN+9 | 43 | SIGRTMAX | 64 |
SIGSEGV | 11 | SIGRTMIN+10 | 44 | ||
SIGUSR2 | 12 | SIGRTMIN+11 | 45 | ||
SIGPIPE | 13 | SIGRTMIN+12 | 46 | ||
SIGALRM | 14 | SIGRTMIN+13 | 47 | ||
SIGTERM | 15 | SIGRTMIN+14 | 48 | ||
SIGSTKFLT | 16 | SIGRTMIN+15 | 49 | ||
SIGCHLD | 17 | SIGRTMAX-14 | 50 | ||
SIGCONT | 18 | SIGRTMAX-13 | 51 | ||
SIGSTOP | 19 | SIGRTMAX-12 | 52 | ||
SIGTSTP | 20 | ||||
SIGTTIN | 21 | ||||
SIGTTOU | 22 | ||||
SIGURG | 23 | ||||
SIGXCPU | 24 | ||||
SIGXFSZ | 25 | ||||
SIGVTALRM | 26 | ||||
SIGPROF | 27 | ||||
SIGWINCH | 28 | ||||
SIGIO | 29 | ||||
SIGPWR | 30 | ||||
SIGSYS | 31 |
发送信号的操作通常由操作系统或其他进程执行。发送信号的常用方法是使用kill命令或系统调用kill()。
①kill():
#include
int kill(pid_t pid, int sig);
功能:往指定进程发送信号
返回值:成功返回0,失败返回-1
参数说明:
pid:向哪个进程发送信号-1:所有进程(不能用)
0:表示发送信号给指定进程ID的进程。sig:具体的某个信号(信号类型)
②raise():
int raise(int sig);
功能:向进程自己发送信号
返回值:成功返回0,失败返回非0
sig:要发送的信号
raise(SIGINT); // <==> kill(getpid(), SIGINT);
#include
#include
#include
void sig_handler(int signum){
if(signum == SIGINT){
printf("收到信号CTRL+C:%d\n",signum);
}
if(signum == SIGQUIT){
printf("收到信号CTRL+\\:%d\n",signum);
}
}
int main(int argc, char *argv[])
{
int sig1 = SIGINT;
int sig2 = SIGQUIT;
//绑定信号
signal(sig1, sig_handler);
signal(sig2, sig_handler);
//自己给自己发信号
raise(sig1);
raise(sig2);
while(1);
return 0;
}
~
③alarm():
unsigned int alarm(unsigned int seconds);
功能:开启定时器进行计时,时间到了产生SIGALRM信号
返回值:上一次定时过后还剩多少秒,如果是第一次定时返回0
seconds:要定时多久,写0表示取消定时
#include
#include
int main(int argc, char *argv[])
{
int ret = alarm(10);
printf("开始计时10秒\n");
printf("上一次还剩下ret 1 = %d 秒\n", ret);
sleep(3);
printf("延迟了三秒\n");
ret = alarm(3);
printf("上一次还剩下ret 2 = %d 秒\n",ret);
while(1);
return 0;
}
④pause():
int pause(void);
功能:暂定进程,需要收到信号才能继续执行
#include
#include
#include
void sig_handler(int signum){
printf("接收到信号 CTRL+C :%d\n",signum);
}
int main(int argc, char *argv[])
{
int sig = SIGINT;
signal(sig, sig_handler);
printf("进程暂停,等待信号……\n");
pause();
printf("进程恢复。\n");
return 0;
}
进程可以使用系统调用signal()来设置信号处理函数,其原型如下:
#include
void (*signal(int signum, void (*handler)(int)))(int);
或者是下面的
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
功能:绑定信号与某个操作
参数说明:
signum:是要设置处理函数的信号编号
handler:是指向信号处理函数的处理方式。SIG_IGN:忽略信号
SIG_DFL:默认操作
或者自定义函数,指定信号发生时需要执行的操作。
信号处理函数的定义如下:
void handler(int signum);
信号处理函数接收一个整数参数signum,它是收到的信号的编号。在信号处理函数中,可以对接收到的信号做出相应的处理,如终止进程、忽略信号等。
对于每个信号,操作系统都有一个默认的信号处理行为。例如,SIGINT信号的默认处理行为是终止进程,而SIGCHLD信号的默认处理行为是忽略。进程可以通过设置信号处理函数来改变默认的处理行为。
信号名 | 含义 | 默认操作 |
---|---|---|
SIGABRT | 中止进程,如调用abort()函数 | 终止进程 |
SIGALRM | 定时器超时 | 终止进程 |
SIGBUS | 非法地址访问(总线错误) | 终止进程 |
SIGCHLD | 子进程状态改变 | 忽略 |
SIGCONT | 继续运行停止的进程 | 忽略 |
SIGFPE | 浮点异常(如除以零) | 终止进程 |
SIGHUP | 终端断开 | 终止进程 |
SIGILL | 非法指令 | 终止进程 |
SIGINT | 终端中断(如按下Ctrl+C) | 终止进程 |
SIGKILL | 杀死进程 | 终止进程 |
SIGPIPE | 管道破裂(写入一个没有读取端) | 终止进程 |
SIGQUIT | 终端退出(如按下Ctrl+\) | 终止进程 |
SIGSEGV | 无效的内存引用 | 终止进程 |
SIGSTOP | 停止进程 | 停止进程 |
SIGTERM | 终止信号(如kill命令) | 终止进程 |
SIGTSTP | 终端挂起(如按下Ctrl+Z) | 停止进程 |
SIGTTIN | 后台进程读终端 | 停止进程 |
SIGTTOU | 后台进程写终端 | 停止进程 |
SIGUSR1 | 用户自定义信号1 | 终止进程 |
SIGUSR2 | 用户自定义信号2 | 终止进程 |
SIGPOLL | I/O事件发生 | 终止进程 |
SIGPROF | 进程运行时间超过时钟周期 | 终止进程 |
SIGSYS | 非法系统调用 | 终止进程 |
SIGTRAP | 跟踪/断点发生 | 终止进程 |
SIGURG | 紧急数据到达套接字 | 忽略 |
SIGVTALRM | 虚拟定时器超时 | 终止进程 |
SIGXCPU | 进程超过CPU时限 | 终止进程 |
SIGXFSZ | 文件大小超过限制 | 终止进程 |
SIGWINCH | 窗口大小发生改变 | 忽略 |
SIG_BLOCK | 阻塞指定的信号 | |
SIG_UNBLOCK | 解除对指定信号的阻塞 | |
SIG_SETMASK | 设置阻塞信号的掩码 |
有时候,我们不希望在某段代码执行期间被某些信号中断。可以使用系统调用sigprocmask()来设置信号屏蔽,从而阻塞某些信号的传递。被屏蔽的信号会在sigprocmask()被调用后暂时被阻塞,直到解除屏蔽为止。