一、信号概述
1. 信号概念
信号是一种在软件层次上对中断机制的模拟,是一种异步通信方式。信号的产生和处理都由操作系统内核完成,用于在进程之间传递信息或通知某些事件的发生。
2. 信号的产生
信号可以通过以下方式产生:
-
按键产生:例如用户按下
Ctrl-C
产生SIGINT
信号,按下Ctrl-\
产生SIGQUIT
信号。 -
系统调用函数产生:例如
kill
、raise
等函数。 -
硬件异常:例如非法指令、除以零等。
-
命令行产生:例如使用
kill
命令向进程发送信号。 -
软件条件:例如访问非法内存、管道写入端关闭等。
3. 信号处理方式
信号可以有以下几种处理方式:
-
缺省方式:执行系统默认的动作。
-
忽略信号:对信号不做任何处理。
-
捕捉信号:通过自定义函数处理信号。
二、常用信号
信号名 | 含义 | 默认操作 |
---|---|---|
SIGHUP | 用户终端关闭时产生,发给与终端关联的会话内的所有进程 | 终止 |
SIGINT | 用户键入Ctrl-C 时产生,发送给当前终端的所有前台进程 | 终止 |
SIGQUIT | 用户键入Ctrl-\ 时产生,与SIGINT 类似 | 终止 |
SIGILL | 进程企图执行非法指令时产生 | 终止 |
SIGSEGV | 非法访问内存时产生,如野指针、缓冲区溢出 | 终止 |
SIGPIPE | 进程往没有读端的管道中写入时产生,代表“管道断裂” | 终止 |
SIGKILL | 用来结束进程,不能被捕捉和忽略 | 终止 |
SIGSTOP | 暂停进程,不能被捕捉和忽略 | 暂停进程 |
SIGTSTP | 用户键入Ctrl-Z 时产生,用于暂停进程 | 暂停进程 |
SIGCONT | 让暂停的进程继续运行 | 继续运行 |
SIGALRM | 定时器时间到时产生 | 终止 |
SIGUSR1 | 保留给用户程序使用的信号 | 终止 |
SIGUSR2 | 保留给用户程序使用的信号 | 终止 |
SIGCHLD | 子进程状态改变时发给父进程 | 忽略 |
三、信号相关函数
1. kill
函数
函数介绍
#include <sys/types.h> #include <signal.h> int kill(pid_t pid, int sig);
-
参数:
-
pid
:目标进程的进程ID。-
> 0
:发送信号给指定进程。 -
= 0
:发送信号给与调用进程处于同一进程组的所有进程。 -
< -1
:发送信号给该进程组的所有进程。 -
= -1
:发送信号给所有有权限发送信号的进程。
-
-
sig
:要发送的信号编号。
-
-
返回值:成功时返回0,失败时返回-1。
-
作用:向指定进程发送信号。
示例代码
#include <stdio.h> #include <signal.h> #include <unistd.h> int main() { pid_t pid = 1234; // 假设目标进程ID为1234 if (kill(pid, SIGINT) < 0) { perror("kill"); return -1; } printf("信号已发送到进程 %d\n", pid); return 0; }
2. raise
函数
函数介绍
#include <signal.h> int raise(int sig);
-
参数:
-
sig
:要发送的信号编号。
-
-
返回值:成功时返回0,失败时返回非0值。
-
作用:向调用进程自身发送信号。
示例代码
#include <stdio.h> #include <signal.h> #include <unistd.h> void handle(int sig) { printf("捕获到信号 %d\n", sig); } int main() { signal(SIGINT, handle); // 设置SIGINT的处理函数 raise(SIGINT); // 向自身发送SIGINT信号 while (1) { sleep(1); } return 0; }
3. alarm
函数
函数介绍
#include <unistd.h> unsigned int alarm(unsigned int seconds);
-
参数:
-
seconds
:定时时间,单位为秒。如果seconds
为0,则清除之前设置的定时器。
-
-
返回值:返回上次设置的定时器剩余时间(秒)。如果之前没有设置定时器,则返回0。
-
作用:设置一个定时器,定时结束后向进程发送
SIGALRM
信号。
示例代码
#include <stdio.h> #include <signal.h> #include <unistd.h> void handle(int sig) { printf("定时器信号捕获到\n"); } int main() { signal(SIGALRM, handle); // 设置SIGALRM的处理函数 alarm(5); // 设置5秒后发送SIGALRM信号 while (1) { sleep(1); } return 0; }
4. ualarm
函数
函数介绍
#include <unistd.h> useconds_t ualarm(useconds_t usecs, useconds_t interval);
-
参数:
-
usecs
:第一次定时的时间,单位为微秒。 -
interval
:触发后的间隔时间,单位为微秒。如果interval
不为0,则定时器会周期性触发。
-
-
返回值:返回上次设置的定时器剩余时间(微秒)。如果之前没有设置定时器,则返回0。
-
作用:设置一个微秒级的定时器,定时结束后向进程发送
SIGALRM
信号,并可以设置定时器的间隔时间。
示例代码
#include <stdio.h> #include <signal.h> #include <unistd.h> void handle(int sig) { printf("定时器信号捕获到\n"); } int main() { signal(SIGALRM, handle); // 设置SIGALRM的处理函数 ualarm(5000000, 1000000); // 5秒后发送SIGALRM信号,之后每隔1秒发送一次 while (1) { sleep(1); } return 0; }
5. setitimer
函数
函数介绍
#include <sys/time.h> int setitimer(int which, const struct itimerval *new_value, struct itimerval *old_value);
-
参数:
-
which
:定时器类型。-
ITIMER_REAL
:以实际时间计时,发送SIGALRM
信号。 -
ITIMER_VIRTUAL
:以用户态运行时间计时,发送SIGVTALRM
信号。 -
ITIMER_PROF
:以用户态和内核态运行时间计时,发送SIGPROF
信号。
-
-
new_value
:指向新的定时器值的结构体。 -
old_value
:指向存储旧的定时器值的结构体(可选)。
-
-
结构体
itimerval
:-
struct timeval it_interval
:定时器的间隔时间。 -
struct timeval it_value
:定时器的初始时间。
-
-
结构体
timeval
:-
time_t tv_sec
:秒。 -
suseconds_t tv_usec
:微秒。
-
-
返回值:成功时返回0,失败时返回-1。
-
作用:设置一个间隔定时器。
示例代码
#include <stdio.h> #include <signal.h> #include <sys/time.h> #include <unistd.h> void handle(int sig) { printf("定时器信号捕获到\n"); } int main() { struct itimerval timer; timer.it_interval.tv_sec = 1; timer.it_interval.tv_usec = 0; timer.it_value.tv_sec = 5; timer.it_value.tv_usec = 0; signal(SIGALRM, handle); // 设置SIGALRM的处理函数 setitimer(ITIMER_REAL, &timer, NULL); // 设置定时器 while (1) { sleep(1); } return 0; }
6. signal
函数
函数介绍
#include <signal.h> typedef void (*sighandler_t)(int); sighandler_t signal(int signum, sighandler_t handler);
-
参数:
-
signum
:要设置的信号编号。 -
handler
:信号处理函数。-
SIG_DFL
:恢复为默认处理方式。 -
SIG_IGN
:忽略信号。 -
其他:自定义处理函数。
-
-
-
返回值:成功时返回之前的信号处理函数,失败时返回
SIG_ERR
。 -
作用:设置信号处理方式。
示例代码
#include <stdio.h> #include <signal.h> #include <unistd.h> void handle(int sig) { printf("捕获到信号 %d\n", sig); } int main() { signal(SIGINT, handle); // 设置SIGINT的处理函数 while (1) { sleep(1); } return 0; }
7. sigaction
函数
函数介绍
#include <signal.h> int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
-
参数:
-
signum
:要设置的信号编号。 -
act
:指向新的信号处理方式的结构体。 -
oldact
:指向存储旧的信号处理方式的结构体(可选)。
-
-
结构体
sigaction
:-
void (*sa_handler)(int)
:信号处理函数。 -
void (*sa_sigaction)(int, siginfo_t *, void *)
:支持传递额外信息的信号处理函数。 -
sigset_t sa_mask
:在信号处理函数执行期间需要屏蔽的信号集。 -
int sa_flags
:信号处理标志。-
SA_SIGINFO
:使用sa_sigaction
成员而不是sa_handler
作为信号处理函数。 -
SA_RESTART
:使被信号打断的系统调用自动重新发起。 -
SA_RESETHAND
:信号处理之后重新设置为默认的处理方式。 -
SA_NODEFER
:使对信号的屏蔽无效,即在信号处理函数执行期间仍能发出这个信号。
-
-
void (*sa_restorer)(void)
:已废弃。
-
-
返回值:成功时返回0,失败时返回-1。
-
作用:设置信号处理方式,功能比
signal
更强大。
示例代码
#include <stdio.h> #include <signal.h> #include <unistd.h> void handle(int sig) { printf("捕获到信号 %d\n", sig); } int main() { struct sigaction act; act.sa_handler = handle; sigemptyset(&act.sa_mask); act.sa_flags = 0; sigaction(SIGINT, &act, NULL); // 设置SIGINT的处理方式 while (1) { sleep(1); } return 0; }
四、信号集操作函数
1. sigemptyset
函数
函数介绍
#include <signal.h> int sigemptyset(sigset_t *set);
-
参数:
-
set
:指向信号集的指针。
-
-
返回值:成功时返回0,失败时返回-1。
-
作用:清空信号集。
示例代码
#include <stdio.h> #include <signal.h> int main() { sigset_t set; sigemptyset(&set); // 清空信号集 return 0; }
2. sigfillset
函数
函数介绍
#include <signal.h> int sigfillset(sigset_t *set);
-
参数:
-
set
:指向信号集的指针。
-
-
返回值:成功时返回0,失败时返回-1。
-
作用:将信号集中的所有信号都设置为1。
示例代码
#include <stdio.h> #include <signal.h> int main() { sigset_t set; sigfillset(&set); // 填充信号集 return 0; }
3. sigaddset
函数
函数介绍
#include <signal.h> int sigaddset(sigset_t *set, int signum);
-
参数:
-
set
:指向信号集的指针。 -
signum
:要添加到信号集中的信号编号。
-
-
返回值:成功时返回0,失败时返回-1。
-
作用:将指定信号添加到信号集中。
示例代码
#include <stdio.h> #include <signal.h> int main() { sigset_t set; sigemptyset(&set); sigaddset(&set, SIGINT); // 添加SIGINT到信号集 return 0; }
4. sigdelset
函数
函数介绍
#include <signal.h> int sigdelset(sigset_t *set, int signum);
-
参数:
-
set
:指向信号集的指针。 -
signum
:要从信号集中移除的信号编号。
-
-
返回值:成功时返回0,失败时返回-1。
-
作用:从信号集中移除指定的信号。
示例代码
#include <stdio.h> #include <signal.h> int main() { sigset_t set; sigfillset(&set); sigdelset(&set, SIGINT); // 从信号集中移除SIGINT return 0; }
5. sigismember
函数
函数介绍
#include <signal.h> int sigismember(const sigset_t *set, int signum);
-
参数:
-
set
:指向信号集的指针。 -
signum
:要检查的信号编号。
-
-
返回值:
-
如果信号在信号集中,返回1。
-
如果信号不在信号集中,返回0。
-
如果出错,返回-1。
-
-
作用:检查指定信号是否在信号集中。
示例代码
#include <stdio.h> #include <signal.h> int main() { sigset_t set; sigemptyset(&set); sigaddset(&set, SIGINT); if (sigismember(&set, SIGINT)) { printf("SIGINT在信号集中。\n"); } else { printf("SIGINT不在信号集中。\n"); } return 0; }
五、信号的阻塞与挂起
1. sigprocmask
函数
函数介绍
#include <signal.h> int sigprocmask(int how, const sigset_t *set, sigset_t *oset);
-
参数:
-
how
:指定如何修改当前信号屏蔽字。-
SIG_BLOCK
:将set
中的信号添加到当前信号屏蔽字中。 -
SIG_UNBLOCK
:从当前信号屏蔽字中移除set
中的信号。 -
SIG_SETMASK
:将当前信号屏蔽字设置为set
中的信号。
-
-
set
:指向新的信号屏蔽集的指针。 -
oset
:指向存储旧的信号屏蔽集的指针(可选)。
-
-
返回值:成功时返回0,失败时返回-1。
-
作用:设置或获取进程的信号屏蔽字。
示例代码
#include <stdio.h> #include <signal.h> #include <unistd.h> void handle(int sig) { printf("捕获到信号 %d\n", sig); } int main() { sigset_t set; sigemptyset(&set); sigaddset(&set, SIGINT); signal(SIGINT, handle); sigprocmask(SIG_BLOCK, &set, NULL); // 阻塞SIGINT信号 sleep(5); // 在这5秒内,SIGINT信号会被阻塞 sigprocmask(SIG_UNBLOCK, &set, NULL); // 解除SIGINT信号的阻塞 while (1) { sleep(1); } return 0; }
2. pause
函数
函数介绍
#include <unistd.h> int pause(void);
-
返回值:总是返回-1,并设置
errno
为EINTR
。 -
作用:使进程挂起,直到接收到信号为止。
示例代码
#include <stdio.h> #include <signal.h> #include <unistd.h> void handle(int sig) { printf("捕获到信号 %d\n", sig); } int main() { signal(SIGINT, handle); printf("进程已挂起。按Ctrl-C继续。\n"); pause(); // 挂起进程 printf("进程已恢复。\n"); return 0; }
3. sigsuspend
函数
函数介绍
#include <signal.h> int sigsuspend(const sigset_t *sigmask);
-
参数:
-
sigmask
:指向信号屏蔽集的指针。
-
-
返回值:总是返回-1,并设置
errno
为EINTR
。 -
作用:将进程的信号屏蔽字设置为
sigmask
,然后挂起进程,直到接收到信号为止。
示例代码
#include <stdio.h> #include <signal.h> #include <unistd.h> void handle(int sig) { printf("捕获到信号 %d\n", sig); } int main() { sigset_t set; sigemptyset(&set); sigaddset(&set, SIGINT); signal(SIGINT, handle); printf("进程已挂起。按Ctrl-C继续。\n"); sigsuspend(&set); // 挂起进程 printf("进程已恢复。\n"); return 0; }
六、使用SIGCHLD
信号回收子进程
1. SIGCHLD
信号
SIGCHLD
信号在以下情况下产生:
-
子进程终止。
-
子进程接收到
SIGSTOP
信号而暂停。 -
子进程从暂停状态被唤醒。
父进程可以通过捕捉SIGCHLD
信号来回收子进程,避免产生僵尸进程。
示例代码
#include <stdio.h> #include <signal.h> #include <sys/wait.h> #include <unistd.h> void handle(int sig) { wait(NULL); // 回收子进程 printf("子进程已终止。信号 %d 收到。\n", sig); } int main() { pid_t pid; struct sigaction act; act.sa_handler = handle; act.sa_flags = 0; sigemptyset(&act.sa_mask); sigaction(SIGCHLD, &act, NULL); // 设置SIGCHLD的处理函数 pid = fork(); if (pid > 0) { // 父进程 while (1) { printf("父进程正在运行。PID: %d\n", getpid()); sleep(1); } } else if (pid == 0) { // 子进程 printf("子进程正在运行。PID: %d\n", getpid()); sleep(5); exit(0); } return 0; }
七、定时器的实现
1. alarm
函数
alarm
函数用于设置一个定时器,当定时时间到达时,系统会向进程发送SIGALRM
信号。
函数原型:
#include <unistd.h> unsigned int alarm(unsigned int seconds);
参数:
-
seconds
:定时时间,单位为秒。如果seconds
为0,则清除之前设置的定时器。
返回值:
-
返回上次设置的定时器剩余时间(秒)。如果之前没有设置定时器,则返回0。
示例代码:
#include <stdio.h> #include <signal.h> #include <unistd.h> void handle_sigalrm(int sig) { printf("定时器信号捕获到\n"); alarm(1); // 重新设置定时器,实现周期性触发 } int main() { signal(SIGALRM, handle_sigalrm); alarm(1); // 设置1秒后触发定时器 printf("等待定时器信号...\n"); while (1) { pause(); } return 0; }
2. ualarm
函数
ualarm
函数用于设置一个微秒级的定时器,当定时时间到达时,系统会向进程发送SIGALRM
信号。它可以设置一次性定时器或周期性定时器。
函数原型:
#include <unistd.h> useconds_t ualarm(useconds_t usecs, useconds_t interval);
参数:
-
usecs
:首次触发的时间,单位为微秒。 -
interval
:触发后的间隔时间,单位为微秒。如果interval
不为0,则定时器会周期性触发。
返回值:
-
返回上次设置的定时器剩余时间(微秒)。如果之前没有设置定时器,则返回0。
示例代码:
#include <stdio.h> #include <signal.h> #include <unistd.h> void handle_sigalrm(int sig) { printf("定时器信号捕获到\n"); } int main() { signal(SIGALRM, handle_sigalrm); ualarm(5000000, 1000000); // 5秒后触发,之后每隔1秒触发一次 printf("等待定时器信号...\n"); while (1) { pause(); } return 0; }
3. setitimer
函数
setitimer
函数用于设置一个间隔定时器,可以指定定时器的类型,并在定时时间到达时发送相应的信号。
函数原型:
#include <sys/time.h> int setitimer(int which, const struct itimerval *new_value, struct itimerval *old_value);
参数:
-
which
:定时器类型,可选值为:-
ITIMER_REAL
:基于实际时间的定时器,触发时发送SIGALRM
信号。 -
ITIMER_VIRTUAL
:基于用户态运行时间的定时器,触发时发送SIGVTALRM
信号。 -
ITIMER_PROF
:基于用户态和内核态运行时间的定时器,触发时发送SIGPROF
信号。
-
-
new_value
:指向新的定时器设置的指针。 -
old_value
:指向存储旧的定时器设置的指针(可选)。
结构体itimerval
:
struct itimerval { struct timeval it_interval; // 定时器的间隔时间 struct timeval it_value; // 定时器的初始时间 };
结构体timeval
:
struct timeval { long tv_sec; // 秒 long tv_usec; // 微秒 };
返回值:
-
成功时返回0,失败时返回-1。
示例代码:
#include <stdio.h> #include <signal.h> #include <sys/time.h> #include <unistd.h> void handle_sigalrm(int sig) { printf("定时器信号捕获到\n"); struct itimerval timer; timer.it_interval.tv_sec = 1; timer.it_interval.tv_usec = 0; timer.it_value.tv_sec = 1; timer.it_value.tv_usec = 0; setitimer(ITIMER_REAL, &timer, NULL); // 重新设置定时器 } int main() { struct itimerval timer; signal(SIGALRM, handle_sigalrm); timer.it_interval.tv_sec = 1; timer.it_interval.tv_usec = 0; timer.it_value.tv_sec = 1; timer.it_value.tv_usec = 0; setitimer(ITIMER_REAL, &timer, NULL); printf("等待定时器信号...\n"); while (1) { pause(); } return 0; }
八、信号的捕捉与处理
1. 信号捕捉过程
信号捕捉的步骤如下:
-
定义信号处理函数,该函数在信号到达时被调用。
-
使用
signal
或sigaction
函数将信号与处理函数关联起来。
2. signal
函数
signal
函数用于设置信号的处理方式。
函数原型:
#include <signal.h> typedef void (*sighandler_t)(int); sighandler_t signal(int signum, sighandler_t handler);
参数:
-
signum
:要设置处理方式的信号编号。 -
handler
:信号处理函数,或者SIG_DFL
(恢复默认处理)、SIG_IGN
(忽略信号)。
返回值:
-
返回之前的信号处理函数,如果设置失败则返回
SIG_ERR
。
示例代码:
#include <stdio.h> #include <signal.h> #include <unistd.h> void handle_sigint(int sig) { printf("SIGINT信号捕获到\n"); } int main() { signal(SIGINT, handle_sigint); printf("进程正在运行。按Ctrl+C发送SIGINT。\n"); while (1) { sleep(1); } return 0; }
3. sigaction
函数
sigaction
函数提供了更灵活的信号处理设置,推荐使用。
函数原型:
#include <signal.h> int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
参数:
-
signum
:要设置处理方式的信号编号。 -
act
:指向新的信号处理动作的指针。 -
oldact
:指向存储旧的信号处理动作的指针(可选)。
结构体sigaction
:
struct sigaction { void (*sa_handler)(int); // 信号处理函数 void (*sa_sigaction)(int, siginfo_t *, void *); // 带额外信息的处理函数 sigset_t sa_mask; // 处理信号时屏蔽的信号集 int sa_flags; // 信号处理标志 void (*sa_restorer)(void); // 已废弃 };
常用sa_flags
标志:
-
SA_SIGINFO
:使用sa_sigaction
而不是sa_handler
。 -
SA_RESTART
:被信号中断的系统调用会自动重新发起。 -
SA_NODEFER
:在信号处理函数执行期间,不对该信号进行屏蔽。
示例代码:
#include <stdio.h> #include <signal.h> #include <unistd.h> void handle_sigint(int sig) { printf("SIGINT信号捕获到\n"); } int main() { struct sigaction act; act.sa_handler = handle_sigint; sigemptyset(&act.sa_mask); act.sa_flags = 0; sigaction(SIGINT, &act, NULL); printf("进程正在运行。按Ctrl+C发送SIGINT。\n"); while (1) { sleep(1); } return 0; }
九、信号的阻塞与挂起
1. 信号的阻塞
信号的阻塞是指阻止信号被处理,但信号仍然可以产生。阻塞信号不会被立即处理,而是等到解除阻塞后才处理。
示例代码
#include <stdio.h> #include <signal.h> #include <unistd.h> void handle(int sig) { printf("捕获到信号 %d\n", sig); } int main() { sigset_t set; sigemptyset(&set); sigaddset(&set, SIGINT); signal(SIGINT, handle); sigprocmask(SIG_BLOCK, &set, NULL); // 阻塞SIGINT信号 sleep(5); // 在这5秒内,SIGINT信号会被阻塞 sigprocmask(SIG_UNBLOCK, &set, NULL); // 解除SIGINT信号的阻塞 while (1) { sleep(1); } return 0; }
2. pause
函数
pause
函数使进程挂起,直到接收到信号为止。如果信号的处理动作是终止进程,则pause
函数不会返回;如果信号的处理动作是忽略,则进程继续挂起;如果信号的处理动作是捕捉,则调用完信号处理函数后,pause
函数返回-1。
示例代码
#include <stdio.h> #include <signal.h> #include <unistd.h> void handle(int sig) { printf("捕获到信号 %d\n", sig); } int main() { signal(SIGINT, handle); printf("进程已挂起。按Ctrl-C继续。\n"); pause(); // 挂起进程 printf("进程已恢复。\n"); return 0; }
3. sigsuspend
函数
sigsuspend
函数将进程的信号屏蔽字设置为指定的信号集,然后挂起进程,直到接收到信号为止。它通常用于在信号处理函数中临时更改信号屏蔽字。
示例代码
#include <stdio.h> #include <signal.h> #include <unistd.h> void handle(int sig) { printf("捕获到信号 %d\n", sig); } int main() { sigset_t set; sigemptyset(&set); sigaddset(&set, SIGINT); signal(SIGINT, handle); printf("进程已挂起。按Ctrl-C继续。\n"); sigsuspend(&set); // 挂起进程 printf("进程已恢复。\n"); return 0; }
十、信号集操作
1. 信号集操作函数
信号集操作函数用于管理信号集,可以清空、填充、添加、删除和检查信号集中的信号。
示例代码
#include <stdio.h> #include <signal.h> int main() { sigset_t set; sigemptyset(&set); // 清空信号集 sigaddset(&set, SIGINT); // 添加SIGINT到信号集 sigaddset(&set, SIGQUIT); // 添加SIGQUIT到信号集 if (sigismember(&set, SIGINT)) { printf("SIGINT在信号集中。\n"); } else { printf("SIGINT不在信号集中。\n"); } if (sigismember(&set, SIGQUIT)) { printf("SIGQUIT在信号集中。\n"); } else { printf("SIGQUIT不在信号集中。\n"); } sigdelset(&set, SIGINT); // 从信号集中删除SIGINT if (sigismember(&set, SIGINT)) { printf("SIGINT在信号集中。\n"); } else { printf("SIGINT不在信号集中。\n"); } return 0; }
十一、信号的忽略与默认处理
1. 忽略信号
可以使用signal
函数将信号处理方式设置为SIG_IGN
,从而忽略指定的信号。
示例代码
#include <stdio.h> #include <signal.h> #include <unistd.h> int main() { signal(SIGINT, SIG_IGN); // 忽略SIGINT信号 printf("SIGINT信号被忽略。按Ctrl+C测试。\n"); while (1) { sleep(1); } return 0; }
2. 恢复默认处理
可以使用signal
函数将信号处理方式设置为SIG_DFL
,从而恢复系统的默认处理方式。
示例代码
#include <stdio.h> #include <signal.h> #include <unistd.h> void handle(int sig) { printf("捕获到信号 %d\n", sig); } int main() { signal(SIGINT, handle); // 设置SIGINT的处理函数 sleep(5); signal(SIGINT, SIG_DFL); // 恢复SIGINT的默认处理方式 printf("SIGINT信号恢复为默认处理。按Ctrl+C测试。\n"); while (1) { sleep(1); } return 0; }
十二、信号在进程间通信中的应用
1. 使用kill
命令发送信号
可以在命令行使用kill
命令向指定进程发送信号。
示例代码
# 向进程ID为1234的进程发送SIGINT信号 kill -SIGINT 1234
2. 使用raise
函数发送信号给自己
可以使用raise
函数向自身发送信号。
示例代码
#include <stdio.h> #include <signal.h> #include <unistd.h> void handle(int sig) { printf("捕获到信号 %d\n", sig); } int main() { signal(SIGINT, handle); // 设置SIGINT的处理函数 raise(SIGINT); // 向自身发送SIGINT信号 while (1) { sleep(1); } return 0; }