学堂 学堂 学堂公众号手机端

37-使用 kill 函数发送信号

lewis 1年前 (2024-04-19) 阅读数 18 #技术


一直以来,我们给程序发送信号都是通过快捷键(​​Ctrl+C, Ctrl+Z, Ctrl+\​​​) 或者使用系统命令​​kill​​​来向进程发送信号(还有一种是系统给你发送的信号,比如 SIGCHLD、SIGSEGV 等等)。除此之外,也可以通过函数 ​​int kill(pid_t pid, int sig)​​​ 来向进程发送信号。​​kill​​ 函数是 POSIX 定义的。

实际上还有一个函数名为 ​​raise​​​,它是 ANSI C 定义的函数(在 ANSI C中就没有多进程的概念,所以该函数是给本进程发信号)。对于单线程的程序来说,​​raise​​​ 函数就是给本进程发信号,相当于​​kill(getpid(), sig)​​​;对于多线程的程序来说,它是给本线程发送信号,相当于​​pthread_kill(pthread_self(), sig)​​(有点扯远了,大家忽略)。


所以,学会了 ​​kill​​​ 函数,自然也就会了 ​​raise​​。

1. kill 函数原型
int kill(pid_t pid, int
参数 pidpid > 0,表示向进程号为 pid 的进程发信号pid = 0,表示向同组进程发信号(有权限才行)pid < -1,向进程组 |pid|pid = -1,向所有进程发信号(有权限才行,早期的 POSIX 并未定义此种情况)

所以,最常用的就是 pid > 0 的情况了,其它情况暂时还不会,因为你还不懂什么是进程组,就此略过,等讲到进程组的概念的时候,自然就懂了。

参数 sig

表示向进程发送什么信号。如果 sig 为 0 ,通常用来测试是否有权限向进程发信号。

2. 实例

这个例子很简单,父进程 fork 出一个子进程,然后该子进程向父进程发送 10 次信号。父进程 fork 完后每 10 称向屏幕打点。

代码
// mykill.c
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <wait.h>
#include <stdio.h>
#include <stdlib.h>


void handler(int sig) {
if (sig == SIGUSR1) {
printf("Hello my child\n");
}
else if (sig == SIGCHLD) {
wait(NULL);
}
}


void child() {
int n = 10;
while(n--) {
if (kill(getppid(), SIGUSR1) == -1) {
perror("kill");
}
sleep(1);
}

exit(0);
}

int main() {
if (SIG_ERR == signal(SIGUSR1, handler)) {
perror("signal SIGUSR1");
}
if (SIG_ERR== signal(SIGCHLD, handler)) {
perror("signal SIGUSR2");
}

pid_t pid = fork();

if (pid == 0) child();
else if (pid == -1) {
perror("fork");
}

while(1) {
write(STDOUT_FILENO, ".", 1);
sleep(10);
}

return 0;
}
编译并运行
$ gcc mykill.c -o mykill
$ ./mykill
结果
.Hello my child
.Hello my child
.Hello my child
.Hello my child
.Hello my child
.Hello my child
.Hello my child
.Hello my child
.Hello my child
.Hello my
结果分析

如果父进程收到子进程发来的信号,父进程在信号处理函数里打印 Hello my child。值得注意的是,每次父进程打印完Hello my child 后就会立即打印一个点,原因后面的文章会讲。

3. 总结掌握 kill 函数掌握 raise 函数(请自己练习)信号会中断父进程的 sleep 函数


版权声明

本文仅代表作者观点,不代表博信信息网立场。

热门