Wait waitpid

转自:http://www.cnblogs.com/mickole/p/3187770.html

linux系统编程之进程(六):父进程查询子进程的退出,wait,waitpid

本节目标:

  • 僵进程
  • SIGCHLD
  • wait
  • waitpid

一,僵尸进程

当一个子进程先于父进程结束运行时,它与其父进程之间的关联还会保持到父进程也正常地结束运行,或者父进程调用了wait才告终止。

子进程退出时,内核将子进程置为僵尸状态,这个进程称为僵尸进程,它只保留最小的一些内核数据结构,以便父进程查询子进程的退出状态。

进程表中代表子进程的数据项是不会立刻释放的,虽然不再活跃了,可子进程还停留在系统里,因为它的退出码还需要保存起来以备父进程中后续的wait调用使用。它将称为一个“僵进程”。

二,如何避免僵尸进程

  • 调用wait或者waitpid函数查询子进程退出状态,此方法父进程会被挂起。
  • 如果不想让父进程挂起,可以在父进程中加入一条语句:signal(SIGCHLD,SIG_IGN);表示父进程忽略SIGCHLD信号,该信号是子进程退出的时候向父进程发送的。

三,SIGCHLD信号

当子进程退出的时候,内核会向父进程发送SIGCHLD信号,子进程的退出是个异步事件(子进程可以在父进程运行的任何时刻终止)

如果不想让子进程编程僵尸进程可在父进程中加入:signal(SIGCHLD,SIG_IGN);

如果将此信号的处理方式设为忽略,可让内核把僵尸子进程转交给init进程去处理,省去了大量僵尸进程占用系统资源。

示例:

复制代码
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>int main(void)
{pid_t pid;if(signal(SIGCHLD,SIG_IGN) == SIG_ERR){perror("signal error");exit(EXIT_FAILURE);}pid = fork();if(pid == -1){perror("fork error");exit(EXIT_FAILURE);}if(pid == 0){printf("this is child process\n");exit(0);}if(pid > 0){sleep(100);printf("this is parent process\n");}return 0;
}
复制代码

结果:

QQ截图20130713104153

可知,虽然子进程先退出了,但进程表中已经不存在子进程的僵尸状态

 

三,wait()函数

#include <sys/types.h> 
#include <sys/wait.h>

pid_t wait(int *status);

进程一旦调用了wait,就立即阻塞自己,由wait自动分析是否当前进程的某个子进程已经退出,如果让它找到了这样一个已经变成僵尸的子进程,wait就会收集这个子进程的信息,并把它彻底销毁后返回;如果没有找到这样一个子进程,wait就会一直阻塞在这里,直到有一个出现为止。 
参数status用来保存被收集进程退出时的一些状态,它是一个指向int类型的指针。但如果我们对这个子进程是如何死掉的毫不在意,只想把这个僵尸进程消灭掉,(事实上绝大多数情况下,我们都会这样想),我们就可以设定这个参数为NULL,就象下面这样:

		pid = wait(NULL);

如果成功,wait会返回被收集的子进程的进程ID,如果调用进程没有子进程,调用就会失败,此时wait返回-1,同时errno被置为ECHILD。

man帮助:

DESCRIPTION 
       All of these system calls are used to wait for state changes in a child 
       of the calling process, and obtain information about  the  child  whose 
       state  has changed.  A state change is considered to be: the child ter- 
       minated; the child was stopped by a signal; or the child was resumed by 
       a  signal.  In the case of a terminated child, performing a wait allows 
       the system to release the resources associated with  the  child;  if  a 
       wait  is not performed, then the terminated child remains in a "zombie" 
       state (see NOTES below).

       If a child has already changed state, then these calls  return  immedi- 
       ately.   Otherwise  they  block until either a child changes state or a 
       signal handler interrupts the call (assuming that system calls are  not 
       automatically restarted using the SA_RESTART flag of sigaction(2)).  In 
       the remainder of this page, a child whose state has changed  and  which 
       has  not  yet  been  waited upon by one of these system calls is termed 
       waitable. 

wait() : 
    The wait() system call suspends execution of the calling process  until 
    one  of  its children terminates.  The call wait(&status) is equivalent 
    to:

        waitpid(-1, &status, 0);

If status is not NULL, wait() and waitpid() store status information in 
      the  int  to  which  it points.  This integer can be inspected with the 
      following macros (which take the integer itself as an argument,  not  a 
      pointer to it, as is done in wait() and waitpid()!):

      WIFEXITED(status) 
             returns true if the child terminated normally, that is, by call- 
             ing exit(3) or _exit(2), or by returning from main().

      WEXITSTATUS(status) 
             returns the exit status of the  child.   This  consists  of  the 
             least  significant  8 bits of the status argument that the child 
             specified in a call to exit(3) or _exit(2) or  as  the  argument 
             for  a  return  statement  in main().  This macro should only be 
             employed if WIFEXITED returned true.

      WIFSIGNALED(status) 
             returns true if the child process was terminated by a signal.

    WTERMSIG(status) 
             returns the number of the signal that caused the  child  process 
             to terminate.  This macro should only be employed if WIFSIGNALED 
             returned true.

      WCOREDUMP(status) 
             returns true if the child produced  a  core  dump.   This  macro 
             should  only  be  employed  if  WIFSIGNALED returned true.  This 
             macro is not specified in POSIX.1-2001 and is not  available  on 
             some  Unix  implementations  (e.g.,  AIX, SunOS).  Only use this 
             enclosed in #ifdef WCOREDUMP ... #endif.

      WIFSTOPPED(status) 
             returns true if the child process was stopped by delivery  of  a 
             signal;  this  is  only possible if the call was done using WUN- 
             TRACED or when the child is being traced (see ptrace(2)).

      WSTOPSIG(status) 
             returns the number of the signal which caused the child to stop. 
             This  macro should only be employed if WIFSTOPPED returned true.


   WIFCONTINUED(status) 
       (since Linux 2.6.10) returns  true  if  the  child  process  was 
       resumed by delivery of SIGCONT.

  • wait系统调用会使父进程暂停执行,直到它的一个子进程结束为止。
  • 返回的是子进程的PID,它通常是结束的子进程
  • 状态信息允许父进程判定子进程的退出状态,即从子进程的main函数返回的值或子进程中exit语句的退出码。
  • 如果status不是一个空指针,状态信息将被写入它指向的位置

可以上述的一些宏判断子进程的退出情况:

QQ截图20130713110230

示例程序:

复制代码
#include <stdio.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <unistd.h>int main(void)
{pid_t pid;pid = fork();if(pid < 0){perror("fork error");exit(EXIT_FAILURE);}if(pid == 0){printf("this is child process\n");exit(100);}int status;pid_t ret;ret = wait(&status);if(ret <0){perror("wait error");exit(EXIT_FAILURE);}printf("ret = %d pid = %d\n", ret, pid);if (WIFEXITED(status))printf("child exited normal exit status=%d\n", WEXITSTATUS(status));else if (WIFSIGNALED(status))printf("child exited abnormal signal number=%d\n", WTERMSIG(status));else if (WIFSTOPPED(status))printf("child stoped signal number=%d\n", WSTOPSIG(status));return 0;
}
复制代码

结果:

QQ截图20130713111249

当子进程正常退出时wait返回子进程pid,且WIFEXITED(status)验证为真,可以WEXITSTATUS(status)获得返回状态码

示例2:

复制代码
#include <stdio.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <unistd.h>int main(void)
{pid_t pid;pid = fork();if(pid < 0){perror("fork error");exit(EXIT_FAILURE);}if(pid == 0){printf("this is child process\n");//exit(100);
        abort();}int status;pid_t ret;ret = wait(&status);if(ret <0){perror("wait error");exit(EXIT_FAILURE);}printf("ret = %d pid = %d\n", ret, pid);if (WIFEXITED(status))printf("child exited normal exit status=%d\n", WEXITSTATUS(status));else if (WIFSIGNALED(status))printf("child exited abnormal signal number=%d\n", WTERMSIG(status));else if (WIFSTOPPED(status))printf("child stoped signal number=%d\n", WSTOPSIG(status));return 0;
}
复制代码

结果:

QQ截图20130713111642

当子进程异常退出时,WIFSIGNALED(status)为真,可用WTERMSIG(status)获得信号

 

四,waitpid()函数

#include <sys/types.h> 
#include <sys/wait.h>

pid_t waitpid(pid_t pid, int *status, int options);

参数:

status:如果不是空,会把状态信息写到它指向的位置,与wait一样

options:允许改变waitpid的行为,最有用的一个选项是WNOHANG,它的作用是防止waitpid把调用者的执行挂起

The value of options is an OR of zero or more  of  the  following  con- 
stants:

WNOHANG     return immediately if no child has exited.

WUNTRACED   also  return  if  a  child  has stopped (but not traced via 
            ptrace(2)).  Status for traced children which have  stopped 
            is provided even if this option is not specified.

WCONTINUED (since Linux 2.6.10) 
            also return if a stopped child has been resumed by delivery 
            of SIGCONT.

返回值:如果成功返回等待子进程的ID,失败返回-1

对于waitpid的p i d参数的解释与其值有关:

pid == -1 等待任一子进程。于是在这一功能方面waitpid与wait等效。

pid > 0 等待其进程I D与p i d相等的子进程。

pid == 0 等待其组I D等于调用进程的组I D的任一子进程。换句话说是与调用者进程同在一个组的进程。

pid < -1 等待其组I D等于p i d的绝对值的任一子进程

wait与waitpid区别:

  • 在一个子进程终止前, wait 使其调用者阻塞,而waitpid 有一选择项,可使调用者不阻塞。
  • waitpid并不等待第一个终止的子进程—它有若干个选择项,可以控制它所等待的特定进程。
  • 实际上wait函数是waitpid函数的一个特例。waitpid(-1, &status, 0);

示例:

复制代码
#include <stdio.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <unistd.h>int main(void)
{pid_t pid;pid = fork();if(pid < 0){perror("fork error");exit(EXIT_FAILURE);}if(pid == 0){printf("this is child process\n");sleep(5);exit(100);}int status;pid_t ret;ret = waitpid(pid,&status,WNOHANG);if(ret <0){perror("wait error");exit(EXIT_FAILURE);}printf("ret = %d pid = %d\n", ret, pid);if (WIFEXITED(status))printf("child exited normal exit status=%d\n", WEXITSTATUS(status));else if (WIFSIGNALED(status))printf("child exited abnormal signal number=%d\n", WTERMSIG(status));else if (WIFSTOPPED(status))printf("child stoped signal number=%d\n", WSTOPSIG(status));return 0;
}
复制代码

结果:

QQ截图20130713112838

可知,option设为WNOHANG,父进程不会等到子进程的退出,即不会阻塞,如果没有子进程退出则立即返回-1,


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/384409.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux系统编程(五)时序竞态

时序竞态产生原因改进总结产生原因 #include <cstdio> #include <stdio.h> #include <sys/time.h> #include <unistd.h> #include <signal.h> #include <stdlib.h> #include <errno.h>void catch_sigalrm(int signo) {printf("…

Linux C++ 简单爬虫

转载&#xff1a;http://blog.csdn.net/orthocenterchocolate/article/details/38665937 方便易用&#xff0c;传入URL&#xff0c;返回对应页面的内容 [cpp] view plaincopy #include <iostream> #include <string> #include <netdb.h> #include <…

Linux系统编程(六)守护进程

Linux系统编程&#xff08;六&#xff09;守护进程一、进程组概念二、会话创建会话的条件守护进程概念守护进程模型创建守护进程一、进程组 概念 进程组&#xff0c;也称之为作业。代表一个或多个进程的集合。每个进程都属于一个进程组。 当父进程&#xff0c;创建子进程的时…

TCP 客户端和服务器端

转自&#xff1a;http://blog.csdn.net/itcastcpp/article/details/39047265 前面几篇中实现的client每次运行只能从命令行读取一个字符串发给服务器&#xff0c;再从服务器收回来&#xff0c;现在我们把它改成交互式的&#xff0c;不断从终端接受用户输入并和server交互。 [cp…

利用多线程实现linux下C语言的聊天室程序:

转载&#xff1a;http://www.360doc.com/content/16/0421/11/478627_552531090.shtml 利用多线程实现linux下C语言的聊天室程序&#xff1a; 客户端代码&#xff1a; threadsend线程负责客户端消息的发送&#xff1b; threadrecv线程负责客户端接受服务器端的消息。 [html] v…

Linux系统编程(七)消息队列

Linux系统编程&#xff08;七&#xff09;消息队列一、什么是消息队列二、消息队列内部原理三、实现消息队列的收发1.发送消息队列2.接收消息队列四、消息队列与命名管道的比较一、什么是消息队列 消息队列提供了一种从一个进程向另一个进程发送一个数据块的方法。每个数据块都…

基于Linux的SOCKET编程之TCP半双工Client-Server聊天程序

转自&#xff1a;http://blog.csdn.net/apollon_krj/article/details/53398448#0-tsina-1-64987-397232819ff9a47a7b7e80a40613cfe1 所谓半双工通信&#xff0c;即通信双方都可以实现接发数据&#xff0c;但是有一个限制&#xff1a;只能一方发一方收&#xff0c;之后交换收发对…

Linux系统编程(八)线程

Linux系统编程&#xff08;八&#xff09;线程一、什么是线程&#xff1f;二、Linux内核线程实现原理线程共享资源线程非共享资源线程优缺点线程控制原语一、什么是线程&#xff1f; LWP&#xff1a;light weight process 轻量级的进程&#xff0c;本质仍是进程(在Linux环境下…

智能算法(GA、DBO等)求解阻塞流水车间调度问题(BFSP)

先做一个声明&#xff1a;文章是由我的个人公众号中的推送直接复制粘贴而来&#xff0c;因此对智能优化算法感兴趣的朋友&#xff0c;可关注我的个人公众号&#xff1a;启发式算法讨论。我会不定期在公众号里分享不同的智能优化算法&#xff0c;经典的&#xff0c;或者是近几年…

Linux socket编程,对套接字进行封装

转自&#xff1a;http://www.cnblogs.com/-Lei/archive/2012/09/04/2670942.html 下面是对socket操作的封装&#xff0c;因为在Linux下写中文到了windows里面会乱码&#xff0c;所以注释用英文来写&#xff0c;有空再查下解决方法吧 socket.h #ifndef SOCKET_H #define SOCKET_…

Linux系统编程(九)线程同步

Linux系统编程&#xff08;九&#xff09;线程同步一、什么是线程同步&#xff1f;二、互斥量三、条件变量pthread_cond_wait函数pthread_cond_signal函数生产者和消费者模型一、什么是线程同步&#xff1f; 线程同步&#xff0c;指一个线程发出某一功能调用时&#xff0c;在没…

linux网络编程(一)网络基础传输知识

linux网络编程&#xff08;一&#xff09;网络传输基础知识一、什么是协议&#xff1f;二、使用步骤典型协议2.网络应用程序设计模式C/S模式B/S模式优缺点3.分层模型4.TCP/IP四层模型通信过程5.协议格式数据包封装以太网帧格式ARP数据报格式IP段格式UDP数据报格式TCP数据报格式…

linux网络编程:使用多进程实现socket同时收发数据

转载&#xff1a;http://blog.csdn.net/li_wen01/article/details/52685844 前面已讲过使用一个进程实现服务端和客户端P2P通信的实例&#xff0c;但是它只能同时处理一个客户端的连接。如果要实现并发处理多个客户端的连接并且实现P2P通信&#xff0c;可以使用多进程来处理。相…

Linux 进程学习(四)------ sigaction 函数

转自&#xff1a;http://www.cnblogs.com/wblyuyang/archive/2012/11/13/2768923.html 使用 sigaction 函数&#xff1a; signal 函数的使用方法简单&#xff0c;但并不属于 POSIX 标准&#xff0c;在各类 UNIX 平台上的实现不尽相同&#xff0c;因此其用途受 到了一定的限制…

linux网络编程(二)高并发服务器

linux网络编程&#xff08;二&#xff09;高并发服务器错误处理高并发服务器多进程并发服务器客户端错误处理 #include "wrap.h"int Bind(int fd, const struct sockaddr* sa, socklen_t salen) {int ret;if ((ret bind(fd, sa, salen)) < 0){perror("bind…

linux知识(一) 程序、进程与线程

linux知识&#xff08;一&#xff09; 程序、进程与线程程序进程程序如何变成进程&#xff1f;线程线程与进程fork和创建新线程的区别优点程序 程序&#xff1a;程序是已编译好的二进制文件&#xff0c;存储在磁盘中&#xff0c;不占用系统资源 程序包括&#xff1a; RO段&am…

linux 信号signal和sigaction理解

转载&#xff1a;http://blog.csdn.net/beginning1126/article/details/8680757 今天看到unp时发现之前对signal到理解实在浅显&#xff0c;今天拿来单独学习讨论下。 signal&#xff0c;此函数相对简单一些&#xff0c;给定一个信号&#xff0c;给出信号处理函数则可&#xff…

linux知识(二)互斥量、信号量和生产者消费者模型

linux知识&#xff08;二&#xff09;互斥量、信号量和生产者消费者模型一、互斥量产生原因二、信号量生产者消费者模型一、互斥量 产生原因 使用多线程常常会碰到数据混乱的问题&#xff0c;那么使用互斥量&#xff0c;相当于“加锁”的操作&#xff0c;将有助于解决数据混乱…

基于Linux的Socket编程之TCP全双工Server-Client聊天程序

转载&#xff1a;http://blog.csdn.net/apollon_krj/article/details/53437764#0-tsina-1-58570-397232819ff9a47a7b7e80a40613cfe1 一、引言&#xff1a; 由于accept函数、read、write、recv、send等函数都是是阻塞式的&#xff0c;在同一个进程之中&#xff0c;只要有任何一个…

数据结构(一)线性表

数据结构&#xff08;一&#xff09;线性表一、线性表定义二、顺序表定义动态数组三、单链表定义不带头结点带头结点头结点与不带头结点的区别头插法与尾插法双链表循环链表循环单链表循环双链表静态链表一、线性表定义 线性表是具有相同数据类型的n个数据元素的有限序列 特点…