上一节提到,当子进程执行结束,父进程还在执行,在父进程结束之前子进程会成为僵尸进程,那么怎么销毁僵尸进程呢?父进程主动接收子进程的返回值。

销毁僵尸进程的方法:

  1:使用wait函数

  2:使用waitpid函数

  3:利用信号

1:使用wait函数销毁僵尸进程

  1. #include <sys/wait.h>
  2.  
  3. pid_t wait(int *status);
  4. // 成功返回终止的子进程id,失败返回-1

  在父进程中调用wait函数以后,如果有子进程已经执行结束,那么子进程传回的返回值将存储到status所指的内存中,但是如果没有子进程执行结束,父进程将会阻塞在wait函数,直到有子进程执行结束,这是一种不好的实现方法。

  1. // wait函数销毁僵尸进程
    #include <iostream>
  2. #include <unistd.h>
  3. #include <sys/wait.h>
  4.  
  5. using namespace std;
  6.  
  7. int main()
  8. {
  9. pid_t pid = fork();
  10. if (pid < ) {
  11. cout << "fork() failed" << endl;
  12. return ;
  13. }
  14.  
  15. if (pid == ) {
  16. return ;
  17. } else {
  18. int status = ;
  19. wait(&status);
  20. if (WIFEXITED(status)) { // 子进程正常结束
  21. cout << "child return: " << WEXITSTATUS(status) << endl;
  22. }
  23.  
  24. sleep();
  25. }
  26.  
  27. return ;
  28. }

2:使用waitpid函数销毁僵尸进程

  wait函数会使程序阻塞,可换用waitpid函数杀死僵尸进程,同时能避免程序阻塞。

  1. #include <sys/wait.h>
  2.  
  3. pid_t waitpid(pid_t pid, int *status, int options);
  4. // 成功返回终止的子进程id,失败返回-1
  5. // pid : 等待终止的子进程id,传-1代码任意子进程终止
  6. // status:和wait函数的参数一样
  7. // options:传递WNOHANG,没有终止的子进程也不进入阻塞状态,返回0
  1. #include <iostream>
  2. #include <unistd.h>
  3. #include <sys/wait.h>
  4.  
  5. using namespace std;
  6.  
  7. int main()
  8. {
  9. pid_t pid = fork();
  10. if (pid < ) {
  11. cout << "fork() failed" << endl;
  12. return ;
  13. }
  14.  
  15. if (pid == ) {
  16. sleep();
  17. return ;
  18. } else {
  19. int status = ;
  20. while (!waitpid(pid, &status, WNOHANG)) {
  21. sleep();
  22. cout << "child proc is not finish" << endl;
  23. }
  24.  
  25. if (WIFEXITED(status)) { // 子进程正常结束
  26. cout << "child return: " << WEXITSTATUS(status) << endl;
  27. }
  28. }
  29.  
  30. return ;
  31. }

3:利用信号销毁僵尸进程

  利用wait函数能销毁僵尸进程,但是会阻塞父进程;利用waitpid也能销毁僵尸进程并且不阻塞父进程,但是也需要不停的去检查子进程结束没有。所以wait及waitpid方式都不完美。于是引入了信号,信号是在特定事件发生时由操作系统向进程发送的消息,接收到消息的进程做信号处理。信号的使用方法是先注册信号,告诉操作系统,当某个信号发生时,要做什么事情。

  signal(SIGCHLD, do_what);  SIGCHLD是子进程结束的信号,当子进程结束时,执行do_what函数。

  其他常用信号,SIGALRM:已到通过调用alarm函数注册的时间;SIGINT:输入CTRL+C

  1. #include <iostream>
  2. #include <cstdlib>
  3. #include <unistd.h>
  4. #include <signal.h>
  5. #include <sys/wait.h>
  6.  
  7. using namespace std;
  8.  
  9. void read_child_proc(int sig)
  10. {
  11. int status;
  12. pid_t pid = waitpid(-, &status, WNOHANG);
  13.  
  14. if (WIFEXITED(status)) { // 子进程正常结束
  15. cout << "child proc finish: " << pid <<" " << WEXITSTATUS(status) << endl;
  16. }
  17. }
  18.  
  19. int main()
  20. {
  21. pid_t pid = fork();
  22. if (pid < ) {
  23. cout << "fork() failed" << endl;
  24. return ;
  25. }
  26.  
  27. signal(SIGCHLD, read_child_proc); // 注册子进程结束信号,当子进程结束时调用read_child_proc函数
  28.  
  29. if (pid == ) {
  30. return ;
  31. } else {
  32. sleep();
  33. cout << "master proc wake up" << endl;
  34. }
  35.  
  36. return ;
  37. }

  执行程序发现 master proc wake up并不是等30秒以后才输出,而输出很快,说明当注册子进程结束信号以后,当有子进程执行结束时,会马上唤醒sleep的进程。

  

C/C++网络编程8——多进程服务器端之销毁僵尸进程的更多相关文章

  1. C/C++网络编程7——多进程服务器端之fork函数

    通过前面几节的内容,我们已经可以实现基本的C/S结构的程序了,但是当多个客户端同时向服务器端请求服务时,服务器端只能按顺序一个一个的服务,这种情况下,客户端的用户是无法忍受的.所以虚实现并发的服务器端 ...

  2. Linux 网络编程详解七(并发僵尸进程处理)

    在上一篇程序框架中,解决了子进程退出,父进程继续存在的功能,但是多条客户端连接如果同一时间并行退出,导致服务器端多个子进程同一时间全部退出,而SIGCHLD是不可靠信号,同时来多条信号可能无法处理,导 ...

  3. C/C++网络编程9——多进程服务器端实现

    #include <iostream> #include <unistd.h> #include <cstdlib> #include <arpa/inet. ...

  4. TCP/IP网络编程之多进程服务端(二)

    信号处理 本章接上一章TCP/IP网络编程之多进程服务端(一),在上一章中,我们介绍了进程的创建和销毁,以及如何销毁僵尸进程.前面我们讲过,waitpid是非阻塞等待子进程销毁的函数,但有一个不好的缺 ...

  5. TCP/IP网络编程之多进程服务端(一)

    进程概念及应用 我们知道,监听套接字会有一个等待队列,里面存放着不同客户端的连接请求,如果有一百个客户端,每个客户端的请求处理是0.5s,第一个客户端当然不会不满,但第一百个客户端就会有相当大的意见了 ...

  6. 网络编程并发 多进程 进程池,互斥锁,信号量,IO模型

    进程:程序正在执行的过程,就是一个正在执行的任务,而负责执行任务的就是cpu 操作系统:操作系统就是一个协调.管理和控制计算机硬件资源和软件资源的控制程序. 操作系统的作用: 1:隐藏丑陋复杂的硬件接 ...

  7. python并发编程之多进程1-----------互斥锁与进程间的通信

    一.互斥锁 进程之间数据隔离,但是共享一套文件系统,因而可以通过文件来实现进程直接的通信,但问题是必须自己加锁处理. 注意:加锁的目的是为了保证多个进程修改同一块数据时,同一时间只能有一个修改,即串行 ...

  8. python并发编程之多进程1--(互斥锁与进程间的通信)

    一.互斥锁 进程之间数据隔离,但是共享一套文件系统,因而可以通过文件来实现进程直接的通信,但问题是必须自己加锁处理. 注意:加锁的目的是为了保证多个进程修改同一块数据时,同一时间只能有一个修改,即串行 ...

  9. python并发编程之多进程1互斥锁与进程间的通信

    一.互斥锁 进程之间数据隔离,但是共享一套文件系统,因而可以通过文件来实现进程直接的通信,但问题是必须自己加锁处理. 注意:加锁的目的是为了保证多个进程修改同一块数据时,同一时间只能有一个修改,即串行 ...

随机推荐

  1. bugku 隐写2

    首先打开链接发现是一张图片 然后分析一下图片 发现这个图片实际是一个压缩包 然后更改一下后缀名 改成zip 然后解压之后会发现另一个压缩包和一张图片压缩包需要密码然后这个图片是一个提示 然后分析 (我 ...

  2. sqli-libs总结

    security数据库中: select left(database(),1)=‘s’;   前1位是否是s: select database() regexp ‘s’;  匹配第一个字符是否是 s: ...

  3. python map、join函数

    map() 会根据提供的函数对指定序列做映射. 第一个参数 function 以参数序列中的每一个元素调用 function 函数,返回包含每次 function 函数返回值的新列表. map(fun ...

  4. MySQL连接

    INNER JOIN(内连接,或等值连接):获取两个表中字段匹配关系的记录. LEFT JOIN(左连接):获取左表所有记录,即使右表没有对应匹配的记录. RIGHT JOIN(右连接): 获取右表所 ...

  5. 金中宝POS

    金中宝POS机刷卡到账时间:9:00-22:00 现代金控自选商户POS机注意事项 选择: 1 消费 T+1到账(下一个工作日到账) 选择: 2 订单支付 是实时到账! 一.金中宝POS机秒到时间:2 ...

  6. Raid5(五块磁盘,三块做raid,两块做备份)

    1.在虚拟中再添加五块磁盘.  2.使用mdadm命令创建raid5,名称为“/dev/md5”. -C代表创建操作,-v显示创建过程,-a yes检查RAID名称,-n是用到的硬盘个数,-l是定义R ...

  7. nginx 解决 connect() failed (111: Connection refused) while connecting to upstream,

    嗯哼,刚装了个ubuntu的lnmp,我的天啊,踩的坑比我脂肪还多了 比如刚装完的时候访问显示502, 也不知道什么问题,就去看了一下nginx日志  /var/log/nginx/error.log ...

  8. js递归生成树形下拉菜单

    需求:我需要把一个单表的数据转换成类似菜单那种如图所示:我呢需要把这个菜单树放入到下框里面去如图所示: 下面是实现思路:1.第一步1.1var afTypeJson=${afTypeJson}// 这 ...

  9. win10无法登陆SSG进行WEB UI管理

    故障描述:尝试登录SSG设备时,无法无法刷出页面,但是设备时可以ping通的(内部接口),可以Telnet上设备,就是无法通过网页登录. 深入测试:win7的系统可以登录,win10的不行,浏览器报协 ...

  10. 洛谷 P1880 [NOI1995]石子合并(区间DP)

    嗯... 题目链接:https://www.luogu.org/problem/P1880 这道题特点在于石子是一个环,所以让a[i+n] = a[i](两倍长度)即可解决环的问题,然后注意求区间最小 ...