二十四、Linux 进程与信号---wait 函数

24.1 wait 函数说明

24.1.1 waitpid---等待子进程中断或结束

  waitpid(等待子进程中断或结束)
  相关函数 wait,fork

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

    • waitpid() 会暂时停止目前进程的执行,直到有信号来到或子进程结束。
    • 如果在调用 wait() 时子进程已经结束,则 wait()会立即返回子进程结束状态值。子进程的结束状态值会由参数 status 返回,而子进程的进程识别码也会一快返回。
    • 如果不在意结束状态值,则参数status可以设成NULL。
  • 函数功能:wait 函数的非阻塞版本
  • 函数参数
    • @pid 为欲等待的子进程识别码,其他数值意义如下:

      • pid< -1 等待其组ID等于 pid 的绝对值的任一子进程
      • pid= -1 等待任一子进程,相当于wait()。
      • pid= 0 等待进程组 ID 等于调用进程的组 ID 的任一子进程
      • pid> 0  等待其进程ID 与 pid 相等的子进程。
    • @option可以为0 或下面的OR 组合
      • WNOHANG 如果没有任何已经结束的子进程则马上返回,不予以等待。(若由 pid 指定的子进程没有退出,则立即返回,则 waitpid 不阻塞,此时其返回值为0,若不设置就为阻塞,相当于wait)
      • WUNTRACED 如果子进程进入暂停执行情况则马上返回,但结束状态不予以理会。(若某实现支持作业控制,则由 pid 指定的任一子进程状态已暂停,且其状态自暂停以来还未报告过,则返回其状态)
    • @status 子进程的结束状态返回后存于 status,底下有几个宏可判别结束情况
      • WIFEXITED(status)  如果子进程正常结束则为非0值。
      • WEXITSTATUS(status)  取得子进程 exit() 返回的结束代码,一般会先用 WIFEXITED 来判断是否正常结束才能使用此宏。
      • WIFSIGNALED(status)  如果子进程是因为信号而结束则此宏值为真(接到一个不能捕捉的信号)
      • WTERMSIG(status)  取得子进程因信号而中止的信号代码,一般会先用 WIFSIGNALED 来判断后才使用此宏。
      • WIFSTOPPED(status) 如果子进程处于暂停执行情况则此宏值为真。一般只有使用 WUNTRACED  时才会有此情况。
      • WSTOPSIG(status) 取得引发子进程暂停的信号代码,一般会先用 WIFSTOPPED  来判断后才使用此宏。
  • 返回值
    • 如果执行成功则返回子进程识别码(PID),如果有错误发生则返回 -1 。失败原因存于 errno 中。

24.1.2 wait --- 等待子进程中断或结束

  wait(等待子进程中断或结束)
  相关函数 waitpid,fork

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

    • wait()会暂时停止目前进程的执行,直到有信号来到或子进程结束。
    • 如果在调用wait()时子进程已经结束,则wait()会立即返回子进程结束状态值。子进程的结束状态值会由参数 status 返回,而子进程的进程识别码也会一快返回。
    • 如果不在意结束状态值,则参数 status 可以设成 NULL。子进程的结束状态值请参考waitpid()。
  • 函数功能:等待子进程退出并回收,防止僵尸进程产生
  • 函数参数
    • @status:为空时,代表任意状态结束的子进程,若不为空,则代表指定状态结束的子进程  
  • 返回值
    • 如果执行成功则返回子进程识别码 (PID),如果有错误发生则返回 -1 。失败原因存于 errno 中。

24.1.3 wait 和 waitpid 函数的区别

  • 在一个子进程终止前,wait 使其调用者阻塞
  • waitpid 由一个选择项,可使调用者不阻塞
  • waitpid 等待一个指定的子进程,而 wait 等待所有的子进程,返回任一终止子进程的状态  

24.2 案例

24.2.1 wait 函数

  process_wait.c

 1 #include <sys/types.h>
 2 #include <sys/wait.h>
 3 #include <unistd.h>
 4 #include <stdio.h>
 5 #include <stdlib.h>
 6
 7
 8 void out_status(int status)
 9 {
10     if(WIFEXITED(status)) {
11         printf("normal exit: %d\n", WEXITSTATUS(status));
12     } else if(WIFSIGNALED(status)) {
13         printf("abnormal term: %d\n", WTERMSIG(status));
14     } else if(WIFSTOPPED(status)) {
15         printf("stopped sig: %d\n", WSTOPSIG(status));
16     } else {
17         printf("unkown sig\n");
18     }
19 }
20
21 int main(void)
22 {
23     int status;//存储子进程终止返回的状态
24     pid_t pid;
25
26     /* 正常终止 */
27     if((pid = fork()) < 0) {
28         perror("fork error");
29         exit(1);
30     } else if(pid == 0) {
31         printf("pid: %d, ppid: %d\n", getpid(), getppid());
32         exit(3);//子进程终止运行
33     }
34
35     //父进程调用wait函数阻塞,等待子进程结束并回收
36     wait(&status);
37     out_status(status);
38     printf("==========================\n");
39
40     /* 非正常终止 */
41     if((pid = fork()) < 0) {
42         perror("fork error");
43         exit(1);
44     } else if(pid == 0) {
45         printf("pid: %d, ppid: %d\n", getpid(), getppid());
46         int i = 3;
47         int j = 0;
48         int k = i / j;
49         printf("k: %d\n", k);
50     }
51
52     wait(&status);
53     out_status(status);
54     printf("==========================\n");
55
56     /* 暂停 */
57     if((pid = fork()) < 0) {
58         perror("fork error");
59         exit(1);
60     } else if(pid == 0) {
61         printf("pid: %d, ppid: %d\n", getpid(), getppid());
62         pause();//暂停,即为阻塞,等待一个信号将它继续运行
63         /*
64         int i = 0;
65         while(++i > 0) sleep(3);*/
66     }
67
68     wait(&status);
69     out_status(status);
70
71     return 0;
72 }

  编译运行:

  

  另开一终端,对进程发出停止信号发现无法停止:

  

  这是因为 WIFSTOPPED(status) 和 WSTOPSIG(status) 必须在使用 waitpid 的 option 参数 WUNTRACED  时候才生效,wait 函数无此功能

22.2.2 waitpid

  process_waitpid.c

 1 #include <sys/types.h>
 2 #include <sys/wait.h>
 3 #include <unistd.h>
 4 #include <stdio.h>
 5 #include <stdlib.h>
 6
 7
 8 void out_status(int status)
 9 {
10     if(WIFEXITED(status)) {
11         printf("normal exit: %d\n", WEXITSTATUS(status));
12     } else if(WIFSIGNALED(status)) {
13         printf("abnormal term: %d\n", WTERMSIG(status));
14     } else if(WIFSTOPPED(status)) {
15         printf("stopped sig: %d\n", WSTOPSIG(status));
16     } else {
17         printf("unkown sig\n");
18     }
19 }
20
21 int main(void)
22 {
23     int status;//存储子进程终止返回的状态
24     pid_t pid;
25
26     /* 正常终止 */
27     if((pid = fork()) < 0) {
28         perror("fork error");
29         exit(1);
30     } else if(pid == 0) {
31         printf("pid: %d, ppid: %d\n", getpid(), getppid());
32         exit(3);//子进程终止运行
33     }
34
35     //父进程调用wait函数阻塞,等待子进程结束并回收
36     wait(&status);
37     out_status(status);
38     printf("==========================\n");
39
40     /* 非正常终止 */
41     if((pid = fork()) < 0) {
42         perror("fork error");
43         exit(1);
44     } else if(pid == 0) {
45         printf("pid: %d, ppid: %d\n", getpid(), getppid());
46         int i = 3;
47         int j = 0;
48         int k = i / j;
49         printf("k: %d\n", k);
50     }
51
52     wait(&status);
53     out_status(status);
54     printf("==========================\n");
55
56     /* 暂停 */
57     if((pid = fork()) < 0) {
58         perror("fork error");
59         exit(1);
60     } else if(pid == 0) {
61         printf("pid: %d, ppid: %d\n", getpid(), getppid());
62         pause();//暂停,即为阻塞,等待一个信号将它继续运行
63         /*
64         int i = 0;
65         while(++i > 0) sleep(3);*/
66     }
67
68     do{
69         //子进程若结束,则 pid 为子进程编号
70         //WNOHANG 非阻塞,waitpid 即子进程还没结束,waitpid 直接返回
71         pid = waitpid(pid, &status, WNOHANG | WUNTRACED);
72         if(pid == 0) sleep(1);//pid = 0, 则子进程没有结束,则父进程睡眠 1 s
73     }while(pid == 0);
74     out_status(status);
75
76     return 0;
77 }

  编译测试与 process_wait.c 一样

  再次发出 kill -19 pid:

  

 

原文地址:https://www.cnblogs.com/kele-dad/p/9147612.html

时间: 2024-10-10 02:10:19

二十四、Linux 进程与信号---wait 函数的相关文章

二十六、Linux 进程与信号---system 函数 和进程状态切换

26.1 system 函数 26.1.1 函数说明 system(执行shell 命令)相关函数 fork,execve,waitpid,popen 1 #include <stdlib.h> 2 int system(const char * string); 函数功能:简化 exec 函数 函数说明 system()会调用 fork() 产生子进程,由子进程来调用 /bin/sh -c string 来执行参数 string 字符串所代表的命令,此命令执行完后随即返回原调用的进程. 在调

(二十四)linux新定时器:timefd及相关操作函数

timerfd是Linux为用户程序提供的一个定时器接口.这个接口基于文件描述符,通过文件描述符的可读事件进行超时通知,所以能够被用于select/poll的应用场景. 一,相关操作函数 #include <sys/timerfd.h> int timerfd_create(int clockid, int flags); int timerfd_settime(int fd, int flags, const struct itimerspec *new_value, struct itim

攻城狮在路上(叁)Linux(二十四)--- linux设置开机挂载及镜像文件挂载

虽然可以手动进行文件系统的挂载,但是每次都手动挂载就会很麻烦,开机挂载的目的就是实现文件系统的自动挂载. 一.开机挂载:/etc/fstab及/etc/mtab 主要是通过修改/etc/fstab文件的配置来实现. fstab是开机时的设置,实际文件系统的挂载是记录到/etc/mtab和/proc/mounts这两个文件中. 1.系统挂载的限制: A.根目录/必须挂载,而且一定是最先挂载的,要先于其他mount point. B.其他挂载点必须为已新建的目录,可以任意指定. C.所有挂载点在同一

实验二十四:SD卡模块

  驱动SD卡是件容易让人抓狂的事情,驱动SD卡好比SDRAM执行页读写,SD卡虽然不及SDRAM的麻烦要求(时序参数),但是驱动过程却有猥琐操作.除此此外,描述语言只要稍微比较一下C语言,描述语言一定会泪流满面,因为嵌套循环,嵌套判断,或者嵌套函数等都是它的痛.. 史莱姆模块是多模块建模的通病,意指结构能力非常脆弱的模块,暴力的嵌套行为往往会击垮模块的美丽身躯,好让脆弱结构更加脆弱还有惨不忍睹,最终搞垮模块的表达能力.描述语言预想驾驭SD卡,关键的地方就是如何提升模块的结构能力.简单而言,描述

QT开发(二十四)——QT文件操作

QT开发(二十四)--QT文件操作 一.QT文件操作简介 QT中的IO操作通过统一的接口简化了文件与外部设备的操作方式,QT中文件被当作一种特殊的外部设备,文件操作与外部设备操作相同. 1.IO操作的主要函数接口 打开设备:bool open(OpenMode mode) 读取数据:QByteArray read(qint64 maxSize) 写入数据:qint64 write(const QByteArray & byteArray) 关闭设备:void close() IO操作的本质是连续

Android学习笔记二十四之ListView列表视图二

Android学习笔记二十四之ListView列表视图二 前面一篇我们介绍了常用的几种适配器的简单实现和ListView的简单使用,这一篇中,我们介绍一下ListView的优化和一些其它的问题. ListView优化方法一 在ListView中,我们最常用的就是自定义Adapter,在我们自定义Adapter中,需要实现两个比较重要的方法getCount()和getView(),前者是负责计算ListView的总Item数,后者是生成Item,有多少个Item就会调用getView()方法多少次

二十四、Android文件的读写

Android的文件读写与JavaSE的文件读写相同,都是使用IO流.而且Android使用的正是JavaSE的IO流,下面我们通过一个练习来学习Android的文件读写. 1.创建一个Android工程 [html] view plaincopy Project name:File BuildTarget:Android2.2 Application name:文件读写 Package name:test.file Create Activity:DateActivity Min SDK Ve

二十四、管道符和作业控制、shell变量、环境变量配置文件

二十四.管道符和作业控制.shell变量.环境变量配置文件一.管道符和作业控制管道符:| 表示把前面文件输出的内容传递给后面的命令.|grep:过滤,指定关键词的命令.|grep 'aaa'.作业控制Ctrl+z:暂停一个任务.等于把当前任务放在了后台,使用fg命令再调回任务里.fg:前台,foreground.bg:后台,将任务调到后台去运行.示例: vim /etc/passwd [1]+ 已停止 vim /etc/passwd可以停止多个任务,被暂停的任务会有编号.想调回哪个就fg 1或者

从零开始学android&lt;android事件的处理方式.二十四.&gt;

在android中一共有 多种事件,每种事件都有自己相对应的处理机制 如以下几种 1 单击事件 View.OnClickListener public abstract void onClick (View v) 单击组件时触发 2 单击事件 View.OnLongClickListener public abstract boolean onLongClick (View v) 长按组件时触发 3 键盘事件 View.OnKeyListener public abstract boolean