C/C++网络编程8——多进程服务器端之销毁僵尸进程
上一节提到,当子进程执行结束,父进程还在执行,在父进程结束之前子进程会成为僵尸进程,那么怎么销毁僵尸进程呢?父进程主动接收子进程的返回值。
销毁僵尸进程的方法:
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——多进程服务器端之销毁僵尸进程的更多相关文章
- C/C++网络编程7——多进程服务器端之fork函数
通过前面几节的内容,我们已经可以实现基本的C/S结构的程序了,但是当多个客户端同时向服务器端请求服务时,服务器端只能按顺序一个一个的服务,这种情况下,客户端的用户是无法忍受的.所以虚实现并发的服务器端 ...
- Linux 网络编程详解七(并发僵尸进程处理)
在上一篇程序框架中,解决了子进程退出,父进程继续存在的功能,但是多条客户端连接如果同一时间并行退出,导致服务器端多个子进程同一时间全部退出,而SIGCHLD是不可靠信号,同时来多条信号可能无法处理,导 ...
- C/C++网络编程9——多进程服务器端实现
#include <iostream> #include <unistd.h> #include <cstdlib> #include <arpa/inet. ...
- TCP/IP网络编程之多进程服务端(二)
信号处理 本章接上一章TCP/IP网络编程之多进程服务端(一),在上一章中,我们介绍了进程的创建和销毁,以及如何销毁僵尸进程.前面我们讲过,waitpid是非阻塞等待子进程销毁的函数,但有一个不好的缺 ...
- TCP/IP网络编程之多进程服务端(一)
进程概念及应用 我们知道,监听套接字会有一个等待队列,里面存放着不同客户端的连接请求,如果有一百个客户端,每个客户端的请求处理是0.5s,第一个客户端当然不会不满,但第一百个客户端就会有相当大的意见了 ...
- 网络编程并发 多进程 进程池,互斥锁,信号量,IO模型
进程:程序正在执行的过程,就是一个正在执行的任务,而负责执行任务的就是cpu 操作系统:操作系统就是一个协调.管理和控制计算机硬件资源和软件资源的控制程序. 操作系统的作用: 1:隐藏丑陋复杂的硬件接 ...
- python并发编程之多进程1-----------互斥锁与进程间的通信
一.互斥锁 进程之间数据隔离,但是共享一套文件系统,因而可以通过文件来实现进程直接的通信,但问题是必须自己加锁处理. 注意:加锁的目的是为了保证多个进程修改同一块数据时,同一时间只能有一个修改,即串行 ...
- python并发编程之多进程1--(互斥锁与进程间的通信)
一.互斥锁 进程之间数据隔离,但是共享一套文件系统,因而可以通过文件来实现进程直接的通信,但问题是必须自己加锁处理. 注意:加锁的目的是为了保证多个进程修改同一块数据时,同一时间只能有一个修改,即串行 ...
- python并发编程之多进程1互斥锁与进程间的通信
一.互斥锁 进程之间数据隔离,但是共享一套文件系统,因而可以通过文件来实现进程直接的通信,但问题是必须自己加锁处理. 注意:加锁的目的是为了保证多个进程修改同一块数据时,同一时间只能有一个修改,即串行 ...
随机推荐
- buuctf
大白 | png图片改高度png图片改高度[外链图片转存失败(img-PojN2D3v-1567086301372)(evernotecid://74A3E6DA-E009-4797-AA60-5DE ...
- 题解【洛谷P5019】[NOIP2018]铺设道路
题目描述 春春是一名道路工程师,负责铺设一条长度为 \(n\) 的道路. 铺设道路的主要工作是填平下陷的地表.整段道路可以看作是 \(n\) 块首尾相连的区域,一开始,第 \(i\) 块区域下陷的深度 ...
- 部署DVWA时的一些问题和解决办法(二)
DVWA reCAPTCHA key: Missing解决方法 编辑 dvwa/config/config.inc.php这个配置文件 $_DVWA[ 'recaptcha_public_key' ] ...
- MySQL存储引擎优化
如何在两种存储引擎中进行选择? ① 是否有事务操作?有,InnoDB. ②是否存储并发修改?有,InnoDB. ③是否追求快速查询,且数据修改较少?是,MyISAM. ④是否使用全文索引?如果不引用第 ...
- Github Pull Request的提出与采纳
这一文来简要介绍一下Github Pull Request(以下简称PR)的使用方法: 作为PR的提出者,如何对某个仓库提交PR,如何根据仓库管理者对所提交PR的反馈对PR进行完善 作为PR的接收者, ...
- JS高级---原型的简单的语法
原型的简单的语法 构造函数,通过原型添加方法,以下语法,手动修改构造器的指向 实例化对象,并初始化,调用方法 <!DOCTYPE html> <html lang="en& ...
- Python(一)list tuple dict set
这篇文章是为了复习之前学的python的数据结构: 原文链接:http://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a ...
- 【MySQL】常用增删改查
目录 1. 文件夹(库) 2. 文件(表) 3. 文件内容(数据) "@ ___ 1. 文件夹(库) # 增 create database db charset utf8; # 查 sho ...
- iOS 开发之 SDWebImage 底层实现原理分析
SDWebImage 是一个比较流行的用于网络图片缓存的第三方类库.这个类库提供了一个支持缓存的图片下载器.为了方便操作者调用,它提供了很多 UI 组件的类别,例如:UIImageView.UIBut ...
- VMware升级到15版本虚拟机黑屏的解决方法
1.启动VMware15虚拟机,在菜单栏找到:虚拟机→管理→更改硬件兼容性 2.打开该项,弹出更改硬件兼容性向导对话框,点 下一步,接下来把硬件兼容性改为Workstation 12.x 3.根据提 ...