【Linux】可重入函数 volatile SIGHLD信号
🌻个人主页:路飞雪吖~
🌠专栏:Linux
目录
一、 🌟可重入函数
二、🌟volatile --- 易变关键字(保持内存可见性)
🌠 volatile 作用
三、🌟SIGCHLD信号
🍔验证子进程 退出 会向父进程发送 SIGCHLD信号:
🍔基于信号进行子进程回收:
🍔一个进程退出父进程可以等待到,若 多个进程 同时退出 父进程可以等待到吗?
🍔 所以我们在回收子进程时,循环式回收:
🍔问题2:10个子进程,6个退出了!会出现什么问题?
🍔 若 单纯的不想让 子进程 形成僵尸状态,不关心 子进程的 退出结果
🌠对于 子进程的等待方式有 4种 方案:
一、 🌟可重入函数
• main函数调用insert函数向⼀个链表head中插⼊节点node1,插入操作分为两步,刚做完第⼀步的时候,因为硬件中断使进程切换到内核,再次回用户态之前检查到有信号待处理,于是切换到 sighandler函数,sighandler也调用insert函数向同一个链表head中插入节点node2,插⼊操作的两步都做完之后从sighandler返回内核态,再次回到用户态就从main函数调用的insert函数中继续往下执行,先前做第⼀步之后被打断,现在继续做完第⼆步。结果是,main函数和sighandler先后向 链表中插⼊两个节点,而最后只有⼀个节点真正插入链表中了。
• 像上例这样,insert函数被不同的控制流程调用,有可能在第⼀次调用还没返回时就再次进入该函 数,这称为重入;
• insert函数访问⼀个全局链表,有可能因为重入而造成错乱,像这样的函数称为不可 重入函数;反之,如果⼀个函数只访问自己的局部变量或参数,则称为可重入(Reentrant)函数。想⼀ 下,为什么两个不同的控制流程调用同⼀个函数,访问它的同⼀个局部变量或参数就不会造成错乱?
• 一个函数,被两个以上的执行流同时进入 --- 重入【重复进入】。
• 出现问题了,就称该函数是 不可重入函数。
• 没出现问题 --- 可重入函数。
• 只要一个函数使用了一个全局的资源【全局链表、数组、红黑树...】,都是不可重入函数。
• 一个函数不会使用任何全局资源,它所使用的所有变量资源 全都是它自己的 函数内部临时的,就为 可重入函数。
如果⼀个函数符合以下条件之⼀则是不可重入的:
• 调用了malloc或free,因为malloc也是用全局链表来管理堆的。
• 调用了标准I/O库函数。标准I/O库的很多实现都以不可重入的方式使用全局数据结构。
二、🌟volatile --- 易变关键字(保持内存可见性)
zxl@Luffy:~/study/stu0604$ cat sig.c
#include <stdio.h>
#include <signal.h>int flag = 0;
void handler(int signo)
{printf("chang flag 0 to 1\n");flag = 1;
}int main()
{signal(2, handler);while(!flag);printf("process quit normal\n");return 0;
}zxl@Luffy:~/study/stu0604$ ./a.out
^Cchang flag 0 to 1
process quit normal
标准情况下,键⼊ CTRL-C ,2号信号被捕捉,执行自定义动作,修改 flag=1 , while 条件不 满足, 退出循环,进程退出。
zxl@Luffy:~/study/stu0604$ cat sig.c
#include <stdio.h>
#include <signal.h>int flag = 0;
void handler(int signo)
{printf("chang flag 0 to 1\n");flag = 1;
}int main()
{signal(2, handler);while(!flag);printf("process quit normal\n");return 0;
}zxl@Luffy:~/study/stu0604$ gcc sig.c -O0
zxl@Luffy:~/study/stu0604$ ./a.out
^Cchang flag 0 to 1
process quit normalzxl@Luffy:~/study/stu0604$ gcc sig.c -O1
zxl@Luffy:~/study/stu0604$ ./a.out
^Cchang flag 0 to 1
^Cchang flag 0 to 1
^\Quit (core dumped)zxl@Luffy:~/study/stu0604$ gcc sig.c -O2
zxl@Luffy:~/study/stu0604$ ./a.out
^Cchang flag 0 to 1
^Cchang flag 0 to 1
^Cchang flag 0 to 1
^Cchang flag 0 to 1
^\Quit (core dumped)
优化情况下,键入 CTRL-C ,2号信号被捕捉,执行自定义动作,修改 flag=1 ,但是 while 条 件依旧满足,进程继续运行!但是很明显flag肯定已经被修改了,但是为何循环依旧执行?很明显, while 循环检查的 flag,并不是内存中最新的 flag,这就存在了数据⼆异性的问题。while 检 测的 flag 其实已经因为优化,被放在了CPU寄存器当中。如何解决呢?很明显需要 volatile :
zxl@Luffy:~/study/stu0604$ cat sig.c
#include <stdio.h>
#include <signal.h>volatile int flag = 0;
void handler(int signo)
{printf("chang flag 0 to 1\n");flag = 1;
}int main()
{signal(2, handler);while(!flag);printf("process quit normal\n");return 0;
}zxl@Luffy:~/study/stu0604$ gcc sig.c -O2
zxl@Luffy:~/study/stu0604$ ./a.out
^Cchang flag 0 to 1
process quit normal
🌠 volatile 作用
保持内存的可见性,告知编译器,被该关键字修饰的变量,不允许被优化,对该 变量的任何操作,都必须在真实的内存中进行操作。
三、🌟SIGCHLD信号
不用直接 wait 的方式,来进行子进程的等待。
子进程在终止时会给父进程发SIGCHLD信号,该信号的默认处理动作是忽略,父进程可以自定义 SIGCHLD信号的处理函数,这样父进程只需专心处理自己的⼯作,不必关心子进程了,子进程终止时会通 知父进程,父进程在信号处理函数中调用 wait 清理子进程即可。
🍔验证子进程 退出 会向父进程发送 SIGCHLD信号:
zxl@Luffy:~/study/stu0604$ cat sig.cc
#include <iostream>
#include <signal.h>
#include <unistd.h>void handler(int signo)
{std::cout << "get a sig: " << signo << " , I am : " << getpid() << std::endl;
}// 1. 验证子进程退出,给父进程发送SIGCHLD
int main()
{signal(SIGCHLD, handler); // 子进程退出后,父进程就能捕捉到子进程发给父进程的退出信号if(fork() == 0)// 子进程{sleep(5);std::cout << "子进程退出" << std::endl;exit(0);}// 父进程 一直不退出while(true){sleep(1);}return 0;
}zxl@Luffy:~/study/stu0604$ ./sig
子进程退出
get a sig: 17 , I am : 2803028 // 父进程收到子进程的退出信号
^C5秒过后,子进程退出,父进程收到 子进程的 17号退出信号
zxl@Luffy:~$ while :; do ps ajx | head -1 && ps ajx | grep sig; sleep 1; donePPID PID PGID SID TTY TPGID STAT UID TIME COMMAND1 971 971 971 ? -1 Ssl 0 0:00 /usr/bin/python3 /usr/share/unattended-upgrades/unattended-upgrade-shutdown --wait-for-signal
2799396 2803028 2803028 2799396 pts/3 2803028 S+ 1001 0:00 ./sig
2803028 2803029 2803028 2799396 pts/3 2803028 S+ 1001 0:00 ./sig
2801629 2803048 2803047 2801629 pts/0 2803047 S+ 1001 0:00 grep --color=auto sigPPID PID PGID SID TTY TPGID STAT UID TIME COMMAND1 971 971 971 ? -1 Ssl 0 0:00 /usr/bin/python3 /usr/share/unattended-upgrades/unattended-upgrade-shutdown --wait-for-signal
2799396 2803028 2803028 2799396 pts/3 2803028 S+ 1001 0:00 ./sig
2803028 2803029 2803028 2799396 pts/3 2803028 Z+ 1001 0:00 [sig] <defunct>
2801629 2803053 2803052 2801629 pts/0 2803052 S+ 1001 0:00 grep --color=auto sig
🍔基于信号进行子进程回收:
zxl@Luffy:~/study/stu0604$ cat sig.cc
#include <iostream>
#include <signal.h>
#include <unistd.h>
#include <sys/wait.h>void handler(int signo)
{std::cout << "get a sig: " << signo << " , I am : " << getpid() << std::endl;pid_t rid = ::waitpid(-1, nullptr, 0);// -1:等待任意子进程 // nullptr: 不关心子进程的终止状态 // 0: 阻塞等待,直到有子进程终止if(rid > 0){std::cout << "子进程退出了, 回收成功, child id: " << rid << std::endl;}
}// 1. 验证子进程退出,给父进程发送SIGCHLD
// 2. 我们可不可以基于信号进行子进程回收呢?
int main()
{signal(SIGCHLD, handler);if(fork() == 0)// 子进程{sleep(5);std::cout << "子进程退出" << std::endl;exit(0);}// 父进程 一直不退出while(true){sleep(1);}return 0;
}zxl@Luffy:~/study/stu0604$ make
g++ -o sig sig.cc -std=c++11
zxl@Luffy:~/study/stu0604$ ./sig
子进程退出
get a sig: 17 , I am : 2803362
子进程退出了, 回收成功, child id: 2803363 // 基于信号回收子进程
^Czxl@Luffy:~$ while :; do ps ajx | head -1 && ps ajx | grep sig; sleep 1; donePPID PID PGID SID TTY TPGID STAT UID TIME COMMAND1 971 971 971 ? -1 Ssl 0 0:00 /usr/bin/python3 /usr/share/unattended-upgrades/unattended-upgrade-shutdown --wait-for-signal
2799396 2803362 2803362 2799396 pts/3 2803362 S+ 1001 0:00 ./sig
2803362 2803363 2803362 2799396 pts/3 2803362 S+ 1001 0:00 ./sig
2801629 2803387 2803386 2801629 pts/0 2803386 S+ 1001 0:00 grep --color=auto sigPPID PID PGID SID TTY TPGID STAT UID TIME COMMAND1 971 971 971 ? -1 Ssl 0 0:00 /usr/bin/python3 /usr/share/unattended-upgrades/unattended-upgrade-shutdown --wait-for-signal
2799396 2803362 2803362 2799396 pts/3 2803362 S+ 1001 0:00 ./sig
2801629 2803393 2803392 2801629 pts/0 2803392 S+ 1001 0:00 grep --color=auto sig
🍔一个进程退出父进程可以等待到,若 多个进程 同时退出 父进程可以等待到吗?
10个信号同时发送给父进程,位图只能记录一次,而 waitpid() 函数 只调用了一次,即便是没有同时到达,先后到达,我们对应的当前进程最多同时记住两个进程 一个正在等待waitpid() ,另一个再来 就会记录到来的信号,但是后续来的位图就不能记录下来了【位图只能保存一个】,正在处理的信号 是被屏蔽的,所以无法被提交,所以 当 多个进程 同时退出 父进程回收所有的子进程 是有风险的【风险:1. 未决信号[已发送给进程但尚未被处理(接收或忽略)的信号] 使用的是位图; 2. 正在处理某一个信号退出,再来其他信号 我们当前被处理的信号是被屏蔽的】。
zxl@Luffy:~/study/stu0604$ cat sig.cc
#include <iostream>
#include <signal.h>
#include <unistd.h>
#include <sys/wait.h>void handler(int signo)
{std::cout << "get a sig: " << signo << " , I am : " << getpid() << std::endl;pid_t rid = ::waitpid(-1, nullptr, 0);// -1:等待任意子进程// nullptr: 不关心子进程的终止状态// 0: 阻塞等待,直到有子进程终止if (rid > 0){std::cout << "子进程退出了, 回收成功, child id: " << rid << std::endl;}
}// 1. 验证子进程退出,给父进程发送SIGCHLD
// 2. 我们可不可以基于信号进行子进程回收呢?
int main()
{signal(SIGCHLD, handler);// 问题1:若有 10 个子进程同时退出呢?// 每一个信号都能回收吗?for (int i = 0; i < 10; i++){if (fork() == 0) // 子进程{sleep(5);std::cout << "子进程退出" << std::endl;exit(0);}}// 父进程 一直不退出while (true){sleep(1);}return 0;
}zxl@Luffy:~/study/stu0604$ make
g++ -o sig sig.cc -std=c++11
zxl@Luffy:~/study/stu0604$ ./sig
子进程退出
子进程退出
get a sig: 17 , I am : 2804394
子进程退出了, 回收成功, child id: 2804395
子进程退出
子进程退出
子进程退出
子进程退出
子进程退出
get a sig: 17 , I am : 2804394
子进程退出了, 回收成功, child id: 2804396
子进程退出
get a sig: 17 , I am : 2804394
子进程退出了, 回收成功, child id: 2804397
子进程退出
get a sig: 17 , I am : 2804394
子进程退出了, 回收成功, child id: 2804398
get a sig: 17 , I am : 2804394
子进程退出了, 回收成功, child id: 2804399
子进程退出
get a sig: 17 , I am : 2804394
子进程退出了, 回收成功, child id: 2804400
^C// 依旧有子进程 没有被回收完 【还处于僵尸状态】
zxl@Luffy:~$ while :; do ps ajx | head -1 && ps ajx | grep sig; sleep 1; donePPID PID PGID SID TTY TPGID STAT UID TIME COMMAND1 971 971 971 ? -1 Ssl 0 0:00 /usr/bin/python3 /usr/share/unattended-upgrades/unattended-upgrade-shutdown --wait-for-signal
2799396 2804394 2804394 2799396 pts/3 2804394 S+ 1001 0:00 ./sig
2804394 2804395 2804394 2799396 pts/3 2804394 S+ 1001 0:00 ./sig
2804394 2804396 2804394 2799396 pts/3 2804394 S+ 1001 0:00 ./sig
2804394 2804397 2804394 2799396 pts/3 2804394 S+ 1001 0:00 ./sig
2804394 2804398 2804394 2799396 pts/3 2804394 S+ 1001 0:00 ./sig
2804394 2804399 2804394 2799396 pts/3 2804394 S+ 1001 0:00 ./sig
2804394 2804400 2804394 2799396 pts/3 2804394 S+ 1001 0:00 ./sig
2804394 2804401 2804394 2799396 pts/3 2804394 S+ 1001 0:00 ./sig
2804394 2804402 2804394 2799396 pts/3 2804394 S+ 1001 0:00 ./sig
2804394 2804403 2804394 2799396 pts/3 2804394 S+ 1001 0:00 ./sig
2804394 2804404 2804394 2799396 pts/3 2804394 S+ 1001 0:00 ./sig
2801629 2804428 2804427 2801629 pts/0 2804427 S+ 1001 0:00 grep --color=auto sigPPID PID PGID SID TTY TPGID STAT UID TIME COMMAND1 971 971 971 ? -1 Ssl 0 0:00 /usr/bin/python3 /usr/share/unattended-upgrades/unattended-upgrade-shutdown --wait-for-signal
2799396 2804394 2804394 2799396 pts/3 2804394 S+ 1001 0:00 ./sig
2804394 2804401 2804394 2799396 pts/3 2804394 Z+ 1001 0:00 [sig] <defunct>
2804394 2804402 2804394 2799396 pts/3 2804394 Z+ 1001 0:00 [sig] <defunct>
2804394 2804403 2804394 2799396 pts/3 2804394 Z+ 1001 0:00 [sig] <defunct>
2804394 2804404 2804394 2799396 pts/3 2804394 Z+ 1001 0:00 [sig] <defunct>
2801629 2804434 2804433 2801629 pts/0 2804433 S+ 1001 0:00 grep --color=auto sig
🍔 所以我们在回收子进程时,循环式回收:
zxl@Luffy:~/study/stu0604$ cat sig.cc
#include <iostream>
#include <signal.h>
#include <unistd.h>
#include <sys/wait.h>void handler(int signo)// 父进程收到子进程的 17号 信号
{std::cout << "get a sig: " << signo << " , I am : " << getpid() << std::endl;while (true)// 循环式回收子进程{pid_t rid = ::waitpid(-1, nullptr, 0);// -1:等待任意子进程// nullptr: 不关心子进程的终止状态// 0: 阻塞等待,直到有子进程终止if (rid > 0){std::cout << "子进程退出了, 回收成功, child id: " << rid << std::endl;}else if(rid < 0)// 当前进程已经没有子进程了{std::cout << "暂时:子进程回收完毕!" << std::endl;break;}}
}// 1. 验证子进程退出,给父进程发送SIGCHLD
// 2. 我们可不可以基于信号进行子进程回收呢?
int main()
{signal(SIGCHLD, handler);// 问题1:若有 10 个子进程同时退出呢?// 每一个信号都能回收吗?for (int i = 0; i < 10; i++)// 创建多个子进程{if (fork() == 0) // 子进程{sleep(5);std::cout << "子进程退出" << std::endl;exit(0);}}// 父进程 一直不退出while (true){sleep(1);}return 0;
}zxl@Luffy:~/study/stu0604$ make
g++ -o sig sig.cc -std=c++11
.zxl@Luffy:~/study/stu0604$ ./sig
子进程退出
子进程退出
子进程退出
get a sig: 17 , I am : 2804762
子进程退出了, 回收成功, child id: 2804763
子进程退出了, 回收成功, child id: 2804764
子进程退出
子进程退出
子进程退出
子进程退出
子进程退出
子进程退出
子进程退出了, 回收成功, child id: 2804765
子进程退出了, 回收成功, child id: 2804766
子进程退出了, 回收成功, child id: 2804767
子进程退出了, 回收成功, child id: 2804768
子进程退出了, 回收成功, child id: 2804769
子进程退出了, 回收成功, child id: 2804772
子进程退出
子进程退出了, 回收成功, child id: 2804770
子进程退出了, 回收成功, child id: 2804771
暂时:子进程回收完毕!
get a sig: 17 , I am : 2804762
暂时:子进程回收完毕!
^Czxl@Luffy:~$ while :; do ps ajx | head -1 && ps ajx | grep sig; sleep 1; donePPID PID PGID SID TTY TPGID STAT UID TIME COMMAND1 971 971 971 ? -1 Ssl 0 0:00 /usr/bin/python3 /usr/share/unattended-upgrades/unattended-upgrade-shutdown --wait-for-signal
2799396 2804762 2804762 2799396 pts/3 2804762 S+ 1001 0:00 ./sig
2804762 2804763 2804762 2799396 pts/3 2804762 S+ 1001 0:00 ./sig
2804762 2804764 2804762 2799396 pts/3 2804762 S+ 1001 0:00 ./sig
2804762 2804765 2804762 2799396 pts/3 2804762 S+ 1001 0:00 ./sig
2804762 2804766 2804762 2799396 pts/3 2804762 S+ 1001 0:00 ./sig
2804762 2804767 2804762 2799396 pts/3 2804762 S+ 1001 0:00 ./sig
2804762 2804768 2804762 2799396 pts/3 2804762 S+ 1001 0:00 ./sig
2804762 2804769 2804762 2799396 pts/3 2804762 S+ 1001 0:00 ./sig
2804762 2804770 2804762 2799396 pts/3 2804762 S+ 1001 0:00 ./sig
2804762 2804771 2804762 2799396 pts/3 2804762 S+ 1001 0:00 ./sig
2804762 2804772 2804762 2799396 pts/3 2804762 S+ 1001 0:00 ./sig
2801629 2804786 2804785 2801629 pts/0 2804785 S+ 1001 0:00 grep --color=auto sigPPID PID PGID SID TTY TPGID STAT UID TIME COMMAND1 971 971 971 ? -1 Ssl 0 0:00 /usr/bin/python3 /usr/share/unattended-upgrades/unattended-upgrade-shutdown --wait-for-signal
2799396 2804762 2804762 2799396 pts/3 2804762 S+ 1001 0:00 ./sig
2801629 2804791 2804790 2801629 pts/0 2804790 S+ 1001 0:00 grep --color=auto sig
🍔问题2:10个子进程,6个退出了!会出现什么问题?
会一直 waitpid() , 就会出现阻塞!一旦阻塞,当前代码 就不能返回,父进程就会受到影响, 所以 使用非阻塞方式去等待子进程。
zxl@Luffy:~/study/stu0604$ cat sig.cc
#include <iostream>
#include <signal.h>
#include <unistd.h>
#include <sys/wait.h>void handler(int signo)// 父进程收到子进程的 17号 信号
{std::cout << "get a sig: " << signo << " , I am : " << getpid() << std::endl;while (true)// 循环式回收子进程{//pid_t rid = ::waitpid(-1, nullptr, 0);pid_t rid = ::waitpid(-1, nullptr, WNOHANG);// 非阻塞方式去等待子进程// -1:等待任意子进程// nullptr: 不关心子进程的终止状态// 0: 阻塞等待,直到有子进程终止if (rid > 0){std::cout << "子进程退出了, 回收成功, child id: " << rid << std::endl;}else if(rid == 0)// 当前父进程 没有子进程退出{std::cout << "退出的子进程已经被全部回收了" << std::endl;break;}else if(rid < 0)// 当前进程已经没有子进程了, 等待失败!{std::cout << "wait error!" << std::endl;break;}}
}// 1. 验证子进程退出,给父进程发送SIGCHLD
// 2. 我们可不可以基于信号进行子进程回收呢?
int main()
{signal(SIGCHLD, handler);// 问题1:若有 10 个子进程同时退出呢?// 每一个信号都能回收吗?// 问题2:10个子进程,6个退出了!会出现什么问题?// 会一直 waitpid() , 就会出现阻塞!一旦阻塞,// 当前代码 就不能返回,父进程就会受到影响,// 所以 使用非阻塞方式去等待子进程for (int i = 0; i < 10; i++)// 创建多个子进程{if (fork() == 0) // 子进程{sleep(5);std::cout << "子进程退出" << std::endl;exit(0);}}// 父进程 一直不退出while (true){sleep(1);}return 0;
}zxl@Luffy:~/study/stu0604$ make
g++ -o sig sig.cc -std=c++11
^[[Azxl@Luffy:~/study/stu0604$ ./sig
子进程退出
子进程退出
get a sig: 17 , I am : 2805761
子进程退出了, 回收成功, child id: 2805762
子进程退出了, 回收成功, child id: 2805763
退出的子进程已经被全部回收了
子进程退出
子进程退出
子进程退出
子进程退出
子进程退出
子进程退出
子进程退出
get a sig: 17 , I am : 2805761
子进程退出了, 回收成功, child id: 2805764
子进程退出
子进程退出了, 回收成功, child id: 2805765
子进程退出了, 回收成功, child id: 2805767
子进程退出了, 回收成功, child id: 2805768
子进程退出了, 回收成功, child id: 2805769
子进程退出了, 回收成功, child id: 2805770
子进程退出了, 回收成功, child id: 2805771
退出的子进程已经被全部回收了
get a sig: 17 , I am : 2805761
退出的子进程已经被全部回收了
get a sig: 17 , I am : 2805761
子进程退出了, 回收成功, child id: 2805766
wait error! // 等待失败,是因为代码中的waitpid()是死循环,
^C // 一直在等待,所以就算子进程全部退出了,还是会一直 waitzxl@Luffy:~$ while :; do ps ajx | head -1 && ps ajx | grep sig; sleep 1; donePPID PID PGID SID TTY TPGID STAT UID TIME COMMAND1 971 971 971 ? -1 Ssl 0 0:00 /usr/bin/python3 /usr/share/unattended-upgrades/unattended-upgrade-shutdown --wait-for-signal
2799396 2805761 2805761 2799396 pts/3 2805761 S+ 1001 0:00 ./sig
2805761 2805762 2805761 2799396 pts/3 2805761 S+ 1001 0:00 ./sig
2805761 2805763 2805761 2799396 pts/3 2805761 S+ 1001 0:00 ./sig
2805761 2805764 2805761 2799396 pts/3 2805761 S+ 1001 0:00 ./sig
2805761 2805765 2805761 2799396 pts/3 2805761 S+ 1001 0:00 ./sig
2805761 2805766 2805761 2799396 pts/3 2805761 S+ 1001 0:00 ./sig
2805761 2805767 2805761 2799396 pts/3 2805761 S+ 1001 0:00 ./sig
2805761 2805768 2805761 2799396 pts/3 2805761 S+ 1001 0:00 ./sig
2805761 2805769 2805761 2799396 pts/3 2805761 S+ 1001 0:00 ./sig
2805761 2805770 2805761 2799396 pts/3 2805761 S+ 1001 0:00 ./sig
2805761 2805771 2805761 2799396 pts/3 2805761 S+ 1001 0:00 ./sig
2801629 2805796 2805795 2801629 pts/0 2805795 S+ 1001 0:00 grep --color=auto sigPPID PID PGID SID TTY TPGID STAT UID TIME COMMAND1 971 971 971 ? -1 Ssl 0 0:00 /usr/bin/python3 /usr/share/unattended-upgrades/unattended-upgrade-shutdown --wait-for-signal
2799396 2805761 2805761 2799396 pts/3 2805761 S+ 1001 0:00 ./sig
2801629 2805801 2805800 2801629 pts/0 2805800 S+ 1001 0:00 grep --color=auto sig
🍔 若 单纯的不想让 子进程 形成僵尸状态,不关心 子进程的 退出结果
就可以手动 设置对 SIGCHLD 进行忽略。将 SIGCHLD的处理动作置为SIG_IGN,这样fork出来的子进程在终止时 会自动清理掉,不会产生僵尸进程,也不会通知父进程。
zxl@Luffy:~/study/stu0604$ cat sig.cc
#include <iostream>
#include <signal.h>
#include <unistd.h>
#include <sys/wait.h>int main()
{// Linux下,将 SIGCHLD的处理动作置为SIG_IGN,这样fork出来的⼦进程在终⽌时会⾃动清理掉::signal(SIGCHLD, SIG_IGN);for (int i = 0; i < 10; i++)// 创建多个子进程{if (fork() == 0) // 子进程{sleep(5);std::cout << "子进程退出" << std::endl;exit(0);}}// 父进程 一直不退出while (true){sleep(1);}return 0;
}zxl@Luffy:~/study/stu0604$ make
g++ -o sig sig.cc -std=c++11
zxl@Luffy:~/study/stu0604$ ./sig
子进程退出
子进程退出
子进程退出
子进程退出
子进程退出
子进程退出
子进程退出
子进程退出
子进程退出
子进程退出
^Czxl@Luffy:~$ while :; do ps ajx | head -1 && ps ajx | grep sig; sleep 1; donePPID PID PGID SID TTY TPGID STAT UID TIME COMMAND1 971 971 971 ? -1 Ssl 0 0:00 /usr/bin/python3 /usr/share/unattended-upgrades/unattended-upgrade-shutdown --wait-for-signal
2799396 2805873 2805873 2799396 pts/3 2805873 S+ 1001 0:00 ./sig
2805873 2805874 2805873 2799396 pts/3 2805873 S+ 1001 0:00 ./sig
2805873 2805875 2805873 2799396 pts/3 2805873 S+ 1001 0:00 ./sig
2805873 2805876 2805873 2799396 pts/3 2805873 S+ 1001 0:00 ./sig
2805873 2805877 2805873 2799396 pts/3 2805873 S+ 1001 0:00 ./sig
2805873 2805878 2805873 2799396 pts/3 2805873 S+ 1001 0:00 ./sig
2805873 2805879 2805873 2799396 pts/3 2805873 S+ 1001 0:00 ./sig
2805873 2805880 2805873 2799396 pts/3 2805873 S+ 1001 0:00 ./sig
2805873 2805881 2805873 2799396 pts/3 2805873 S+ 1001 0:00 ./sig
2805873 2805882 2805873 2799396 pts/3 2805873 S+ 1001 0:00 ./sig
2805873 2805883 2805873 2799396 pts/3 2805873 S+ 1001 0:00 ./sig
2801629 2805907 2805906 2801629 pts/0 2805906 S+ 1001 0:00 grep --color=auto sigPPID PID PGID SID TTY TPGID STAT UID TIME COMMAND1 971 971 971 ? -1 Ssl 0 0:00 /usr/bin/python3 /usr/share/unattended-upgrades/unattended-upgrade-shutdown --wait-for-signal
2799396 2805873 2805873 2799396 pts/3 2805873 S+ 1001 0:00 ./sig
2801629 2805913 2805912 2801629 pts/0 2805912 S+ 1001 0:00 grep --color=auto sig
🌠对于 子进程的等待方式有 4种 方案:
• 阻塞等待
• 非阻塞等待
• 基于信号进行回收
• 设置对应的::signal(SIGCHLD, SIG_IGN);就可以不让子进程产生僵尸了。
Linux下,SIGCHLD 就为 IGN,直接设置为 空,而 用户设置 IGN 的时候,就可能是 1,Linux 下 和 用户设置的 IGN 是不一样的,Linux 把 为空/为1 做了特殊处理。
如若对你有帮助,记得关注、收藏、点赞哦~ 您的支持是我最大的动力🌹🌹🌹🌹!!!
若有误,望各位,在评论区留言或者私信我 指点迷津!!!谢谢 ヾ(≧▽≦*)o \( •̀ ω •́ )/