子进程的异步等待方式

我们知道当一个父进程创建一个子进程时,会调用wait()和waitpid()函数清理僵?进程,?进程可以阻塞等待?进程结束,也可以?阻塞地查询是否有?进程结束等待清理(也就是轮询的?式)。采?第?种?式,?进程阻塞了就不 能处理??的?作了;采?第?种?式,?进程在处理??的?作的同时还要记得时不时地轮询? 下,程序实现复杂。

1.wait()和waitpid()

(1)wait 函数:用来等待任何一个子进程退出,由父进程调用。

1 #include<sys/types.h>
2 #include<sys/wait.h>
3 pid_t  wait(int* status);

返回值:成功返回被等待子进程的pid,失败返回-1。 status:输出型参数,拿回子进程的退出信息。如果参数status不为空,则进程终止状态被保存于其中。 wait方式:阻塞式等待,等待的子进程不退出时,父进程一直不退出。 目的:回收子进程,系统回收子进程的空间。

依据传统,返回的整形状态字是由实现定义的,其中有些位表示退出状态(正常返回),其他位表示信号编号(异常返回),有一位表示是否产生了一个core文件等。 终止状态是定义在 sys/wait.h中的各个宏,有四可互斥的宏可以用来取得进程终止的原因。

WIFEXITED:正常返回时为真,可以执行宏函数 WEXITSTATUS获取子进程传送给exit、_exit或_Exit的参数的低8位。

WIFSIGNALED :异常返回时为真,可以执行宏函数WTERMSIG取得子进程终止的信号编号,另外,对于一些实现,定义有宏WCOREDUMP宏,若以经昌盛终止进程的core文件,则为真。

WIFSTOPPED :若为当前暂停子进程的返回的状态,则为真,可执行WSTOPSIG取得使子进程暂停的信号编号。

WIFCONTINUED:若在作业控制暂停后已经继续的子进程返回了状态,则为真,仅用于waitpid。

(2)waitpid:

1 #include<sys/types.h>
2 #include<sys/wait.h>
3 pid_t waitpid(pid_t pid,int* status,int options);

1>参数

从参数的名字pid和类型pid_t中就可以看出,这里需要的是一个进程ID。但当pid取不同的值时,在这里有不同的意义。

pid>0时,只等待进程ID等于pid的子进程,不管其它已经有多少子进程运行结束退出了,只要指定的子进程还没有结束,waitpid就会一直等下去。

pid=-1时,等待任何一个子进程退出,没有任何限制,此时waitpid和wait的作用一模一样

pid=0时,等待同一个进程组中的任何子进程,如果子进程已经加入了别的进程组,waitpid不会对它做任何理睬。

pid<-1时,等待一个指定进程组中的任何子进程,这个进程组的ID等于pid的绝对值。

status参数与wait()函数的基本相同。

options参数 当options参数为0时,与wait功能相同,仍是阻塞式等待,不提供额外功能,如果为下列常量按位或则提供更多功能:

WCONTINUED:若实现支持作业控制,那么由pid指定的任一子进程在暂停后已经继续,但状态尚未报告,则返回状态

WNOHANG:若由pid指定的子进程并不是立即可用的,则waitpid不阻塞,即此时以非阻塞方式(轮询式访问的必要条件)等待子进程,并且返回0。

WUNTRACED:若实现支持作业控制,而pid指定的任一子进程已经暂停,且其状态尚未报告,则返回其状态

2>返回值:

当正常返回的时候,waitpid返回收集到的子进程的进程ID;

如果设置了选项WNOHANG,而调用中waitpid发现没有已退出的子进程可收集,则返回0;

如果调用中出错,则返回-1,这时errno会被设置成相应的值以指示错误所在;

当pid所指示的子进程不存在,或此进程存在,但不是调用进程的子进程,waitpid就会出错返回,这时errno被设置为ECHILD;

3>waitpid提供了三个wait所没有的功能:

1. waitpid可等待一个特定的进程

2. waitpid提供了一个wait的非阻塞版本

3. waitpid支持作业控制

2.关于SIGCHLD信号

其实,?进程在终?时会给?进程发SIGCHLD信号,该信号的默认处理动作是忽略,?进程可以? 定义SIGCHLD信号的处理函数,这样?进程只需专?处理??的?作,不必关??进程了,?进程 终?时会通知?进程,?进程在信号处理函数中调?wait清理?进程即可。
一般情况下父进程收到这个信号的默认处理是忽略这个信号,即就是不做任何处理,但是我们可以通过系统调用API:signal()来进行自定义处理句柄,进行验证,具体代码如下:

(1)验证子进程退出时会给父进程发送SIGCHLD信号

程序完成以下功能:?进程fork出?进程,?进程调?exit(1) 终?,?进程?定义SIGCHLD信号的处理函数,在其中调?wait获得?进程的退出状态并打印。

用kill -l指令查看17号信号:

3.子进程的异步等待方式

(1)异步回收僵尸进程:

fork()之后,非阻塞(异步)等待子进程(回收僵尸)。

fork()之后,子进程和父进程分叉执行,僵尸进程的产生是因为父进程没有给子进程“收尸”造成的,又可以根据危害程度分为下述两类:

总体来说:当子进程结束之后,但父进程未结束之前,子进程将成为僵尸进程。

1)当子进程结束之后,但父进程未结束之前,子进程将成为僵尸进程,父进程结束后僵尸被init进程回收。

2)如果子进程结束了,但是父进程始终没有结束,那么这个僵尸将一直存在,而且随着exec,僵尸越来越多。

(2)实现代码

 1 #include<stdio.h>
 2 #include<stdlib.h>
 3 #include<signal.h>
 4 #include<unistd.h>
 5 #include<sys/types.h>
 6 #include<sys/wait.h>
 7 void catchSig(int sig)
 8 {
 9      printf("father is catching,child is quit\n");
10      //以非阻塞方式等待所有异常退出的子进程
11      pid_t id;
12      while((id = waitpid(-1,NULL,WNOHANG)) > 0)
13      {
14          printf("wait child success:%d\n",id);
15     }
16  }
17  int main()
18  {
19       signal(SIGCHLD,catchSig);
20       pid_t pid1 = fork();
21       if(pid1 == 0)//child1
22       {
23           printf("child1:my pid is %d\n",getpid());
24           exit(-1);//子进程1异常终止
25       }
26       pid_t pid2 = fork();//child2
27       if(pid2 == 0)
28       {
29           printf("child2:my pid is %d\n",getpid());
30           exit(-1);//子进程2异常退出
31       }
32       pid_t pid3 = fork();//child3
33       if(pid3 == 0)
34       {
35           printf("child3:my pid is %d\n",getpid());//子进程3正常运行 
36       }
37       while(1)
38       {
39          printf("father is waiting...\n");
40          sleep(1);
41       }
42       return 0; 

运行结果:

时间: 2024-11-07 01:08:57

子进程的异步等待方式的相关文章

python subprocess模块 监控子进程的2种方式 忙等待和立即返回同时设置子进程超时

下面的资料是关于python subprocess模块 监控子进程的2种方式 忙等待和立即返回同时设置子进程超时时间的代码. import subprocess import os import time tt = '555' cmd = "python /home/100003/python/mypython/sub2.py "+" 333"+" 444 "+tt print time.time() sub2 = subprocess.Pope

Socket层实现系列 — 信号驱动的异步等待

主要内容:Socket的异步通知机制. 内核版本:3.15.2 我的博客:http://blog.csdn.net/zhangskd 概述 socket上定义了几个IO事件:状态改变事件.有数据可读事件.有发送缓存可写事件.有IO错误事件. 对于这些事件,socket中分别定义了相应的事件处理函数,也称回调函数. Socket I/O事件的处理过程中,要使用到sock上的两个队列:等待队列和异步通知队列,这两个队列中 都保存着等待该Socket I/O事件的进程. Q:为什么要使用两个队列,等待

开启子进程的两种方式,孤儿进程与僵尸进程,守护进程,互斥锁,IPC机制,生产者与消费者模型

开启子进程的两种方式 # # # 方式一: # from multiprocessing import Process # import time # # def task(x): # print('%s is running' %x) # time.sleep(3) # print('%s is done' %x) # # if __name__ == '__main__': # # Process(target=task,kwargs={'x':'子进程'}) # p=Process(tar

iOS开发——网络编程Swift篇&amp;(四)异步Get方式

异步Get方式 1 // MARK: - 异步Get方式 2 func asynchronousGet() 3 { 4 //创建NSURL对象 5 var url:NSURL! = NSURL(string: "http://m.weather.com.cn/data/101010100.html") 6 7 //创建请求对象 8 var urlRequest : NSURLRequest = NSURLRequest(URL: url, cachePolicy: NSURLReque

iOS开发——网络编程Swift篇&amp;(六)异步Post方式

异步Post方式 1 // MARK: - 异步Post方式 2 func asynchronousPost() 3 { 4 //创建NSURL对象 5 var url:NSURL! = NSURL(string: "http://m.weather.com.cn/data/101010100.html") 6 7 //创建请求对象 8 var request : NSMutableURLRequest = NSMutableURLRequest(URL: url, cachePoli

selenium中的三种等待方式(显示等待WebDriverWait()、隐式等待implicitly()、强制等待sleep())---基于python

我们在实际使用selenium或者appium时,等待下个等待定位的元素出现,特别是web端加载的过程,都需要用到等待,而等待方式的设置是保证脚本稳定有效运行的一个非常重要的手段,在selenium中(appium通用)常用的等待分为显示等待WebDriverWait().隐式等待implicitly_wait().强制等待sleep()三种,下面我们就分别介绍一下这三种等待的区别 在前面的博文中简单介绍了<强制等待和隐士等待的区别和理解>,本文再详细的结合案例进行理解. sleep(): 强

异步等待(ManualResetEvent

ManualResetEvent实现异步等待,超过时间 不做处理,继续往下执行代码 (ManualResetEvent 涉及一个线程在其他线程进行之前必须完成的任务) 1 ManualResetEvent[] mre = new ManualResetEvent[2]; 2 3 mre[0] = new ManualResetEvent(false); 4 shoppingbll spb = new shoppingbll(mre[0], dict); 5 Thread thd1 = new T

NSURLConnection的异步请求方式

iOS5.0 SDK NSURLConnection类新增的sendAsynchronousRequest:queue:completionHandler:方法 sendAsynchronousRequest可以很容易地使用NSURLRequest接收回调,完成http通信. 1. post数据 1 - (void)httpAsynchronousRequest{ 2 3 NSURL *url = [NSURL URLWithString:@"http://url"]; 4 5 NSS

Selenium中的几种等待方式,需特别注意implicitlyWait的用法(转)

最近在项目过程中使用selenium 判断元素是否存在的时候 遇到一个很坑爹的问题, 用以下方法执行的时候每次都会等待很长一段时间,原因是因为对selenium实现方法了解不足导致一直找不到解决方法. private boolean isElementPresent(By by) {     try { driver.findElement(by);       return true;     } catch (NoSuchElementException e) {       return