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

销毁僵尸进程的方法:

  1:使用wait函数

  2:使用waitpid函数

  3:利用信号

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

#include <sys/wait.h>

pid_t wait(int *status);
// 成功返回终止的子进程id,失败返回-1

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

// wait函数销毁僵尸进程
#include <iostream>
#include <unistd.h>
#include <sys/wait.h> using namespace std; int main()
{
pid_t pid = fork();
if (pid < ) {
cout << "fork() failed" << endl;
return ;
} if (pid == ) {
return ;
} else {
int status = ;
wait(&status);
if (WIFEXITED(status)) { // 子进程正常结束
cout << "child return: " << WEXITSTATUS(status) << endl;
} sleep();
} return ;
}

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

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

#include <sys/wait.h>

pid_t waitpid(pid_t pid, int *status, int options);
// 成功返回终止的子进程id,失败返回-1
// pid : 等待终止的子进程id,传-1代码任意子进程终止
// status:和wait函数的参数一样
// options:传递WNOHANG,没有终止的子进程也不进入阻塞状态,返回0
#include <iostream>
#include <unistd.h>
#include <sys/wait.h> using namespace std; int main()
{
pid_t pid = fork();
if (pid < ) {
cout << "fork() failed" << endl;
return ;
} if (pid == ) {
sleep();
return ;
} else {
int status = ;
while (!waitpid(pid, &status, WNOHANG)) {
sleep();
cout << "child proc is not finish" << endl;
} if (WIFEXITED(status)) { // 子进程正常结束
cout << "child return: " << WEXITSTATUS(status) << endl;
}
} return ;
}

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

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

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

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

#include <iostream>
#include <cstdlib>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h> using namespace std; void read_child_proc(int sig)
{
int status;
pid_t pid = waitpid(-, &status, WNOHANG); if (WIFEXITED(status)) { // 子进程正常结束
cout << "child proc finish: " << pid <<" " << WEXITSTATUS(status) << endl;
}
} int main()
{
pid_t pid = fork();
if (pid < ) {
cout << "fork() failed" << endl;
return ;
} signal(SIGCHLD, read_child_proc); // 注册子进程结束信号,当子进程结束时调用read_child_proc函数 if (pid == ) {
return ;
} else {
sleep();
cout << "master proc wake up" << endl;
} return ;
}

  执行程序发现 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. buuctf

    大白 | png图片改高度png图片改高度[外链图片转存失败(img-PojN2D3v-1567086301372)(evernotecid://74A3E6DA-E009-4797-AA60-5DE ...

  2. 题解【洛谷P5019】[NOIP2018]铺设道路

    题目描述 春春是一名道路工程师,负责铺设一条长度为 \(n\) 的道路. 铺设道路的主要工作是填平下陷的地表.整段道路可以看作是 \(n\) 块首尾相连的区域,一开始,第 \(i\) 块区域下陷的深度 ...

  3. 部署DVWA时的一些问题和解决办法(二)

    DVWA reCAPTCHA key: Missing解决方法 编辑 dvwa/config/config.inc.php这个配置文件 $_DVWA[ 'recaptcha_public_key' ] ...

  4. MySQL存储引擎优化

    如何在两种存储引擎中进行选择? ① 是否有事务操作?有,InnoDB. ②是否存储并发修改?有,InnoDB. ③是否追求快速查询,且数据修改较少?是,MyISAM. ④是否使用全文索引?如果不引用第 ...

  5. Github Pull Request的提出与采纳

    这一文来简要介绍一下Github Pull Request(以下简称PR)的使用方法: 作为PR的提出者,如何对某个仓库提交PR,如何根据仓库管理者对所提交PR的反馈对PR进行完善 作为PR的接收者, ...

  6. JS高级---原型的简单的语法

    原型的简单的语法 构造函数,通过原型添加方法,以下语法,手动修改构造器的指向 实例化对象,并初始化,调用方法 <!DOCTYPE html> <html lang="en& ...

  7. Python(一)list tuple dict set

    这篇文章是为了复习之前学的python的数据结构: 原文链接:http://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a ...

  8. 【MySQL】常用增删改查

    目录 1. 文件夹(库) 2. 文件(表) 3. 文件内容(数据) "@ ___ 1. 文件夹(库) # 增 create database db charset utf8; # 查 sho ...

  9. iOS 开发之 SDWebImage 底层实现原理分析

    SDWebImage 是一个比较流行的用于网络图片缓存的第三方类库.这个类库提供了一个支持缓存的图片下载器.为了方便操作者调用,它提供了很多 UI 组件的类别,例如:UIImageView.UIBut ...

  10. VMware升级到15版本虚拟机黑屏的解决方法

    1.启动VMware15虚拟机,在菜单栏找到:虚拟机→管理→更改硬件兼容性 2.打开该项,弹出更改硬件兼容性向导对话框,点  下一步,接下来把硬件兼容性改为Workstation 12.x 3.根据提 ...