当前位置:   article > 正文

【Linux详解】进程等待 | 非阻塞轮询_linux:非阻塞等待

linux:非阻塞等待

引入

为什么?是什么?怎么办

是什么?

进程等待是指父进程暂停自己的执行,直到某个特定的子进程结束或发生某些特定的事件。

为什么?

  • 僵尸进程刀枪不入,不可被杀死,存在内存泄露
  • 获取进程的执行情况,知道我布置给子进程的任务,它完成的怎么样了–可选

怎么办

wait 函数

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

pid_t wait(int* status);
  • 1
  • 2
  • 3
  • 4

测试:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
 
int main (
    void
    ) 
{
    pid_t id = fork();
    if (id == 0) {
        // child
        while (1) {
            printf("我是子进程,我正在运行... Pid: %d\n", getpid());
            sleep(1);
        }
    }
    else {
        printf("我是父进程: pid: %d,我将耐心地等待子进程!\n", getpid());
        sleep(20);   // 为了便于观察,我们让父进程休眠20s
 
        // 苏醒后,父进程执行 wait,耐心地等待子进程
        pid_t ret = wait(NULL);  // 暂且将status参数设置为NULL
        if (ret < 0) {
            printf("等待失败!\n");
        }
        else {
            printf("等待成功!\n");   // 此时 Z → X
        }
 
        sleep(20);  // 子进程退出后,再让父进程存在一段时间
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

在这里插入图片描述

为什么是交替型,不是一个执行完?//了解循环的细节

fork 创建子进程后,父进程会首先执行并打印这条信息,其中 <父进程的pid> 是父进程的进程ID。截不下就没截了

  • 父进程打印一次消息后休眠20秒:
    • 父进程仅在创建子进程后打印一次消息,然后休眠20秒等待观察子进程的活动,不再进行其他操作。

通过这种方式,父进程和子进程能够并发地执行各自的任务,并且我们通过延迟父进程的退出能观察到子进程的连续活动。

整个程序执行流程如下:
  1. 父进程打印:

    yamlCopy code
    我是父进程: pid: 1234,我将耐心地等待子进程!
    
    • 1
    • 2
  2. 子进程每秒打印一次:

    yamlCopy code
    我是子进程,我正在运行... Pid: 5678
    
    • 1
    • 2

    (此循环持续到子进程被终止)

  3. 通过终端输入 kill 5678 终止子进程。

  4. 父进程20秒后苏醒并等待子进程结束后,打印:

    textCopy code
    等待成功!
    
    • 1
    • 2

之后,父进程再休眠20秒并继续存在一段时间后退出


waitpid

刚才讲的 wait 并不是主角,因为其功能比较简单,在进程等待时用的更多的是 waitpid

waitpid 可以把 wait 完全包含,wait 是 waitpid 的一个子功能。

参数

  • pid
    
    • 1

    :要等待的子进程的进程ID。根据传入的值可以指定等待任何子进程、特定进程ID的子进程、任何同一进程组的子进程或者任何同一会话的子进程。

    • 如果 pid 大于零,waitpid 将等待指定进程ID的子进程结束。
    • 如果 pid 等于 -1,waitpid 将等待任意子进程结束,等同于 wait 函数。
  • status:一个指向整型的指针,是一个输出型参数,它将用于存储子进程的终止状态

  • options
    
    • 1

    :用于指定等待行为的附加选项。

    • 传入0表示以默认行为等待子进程。(阻塞等待中再讲)

返回值

  • 如果 waitpid 成功,返回值是已终止子进程的进程ID
  • 如果出现错误,返回-1,并且会设置 errno 变量来指示具体错误原因。

Z状态,其本质上就是将自己的 task_struct 维护起来(代码可以释放,但是 task_struct 必须维护)。所谓的 wait/waitpid 的退出信息,实际上就是从子进程的 task_struct 中拿出来的,即 从子进程的 task_struct 中拿出子进程退出的退出码,拷贝到父进程中

在这里插入图片描述

status

该参数是一个 输出型参数 (即通过调用该函数,从函数内部拿出来特定的数据)。整数的低 16 位,其中又可以分为 最低八位次低八位(具体细节看图):

img

1.次低八位:拿子进程退出码
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/wait.h>
 
int main (
    void
    ) 
{
    pid_t id = fork();
    if (id == 0) {
        int cnt = 5;   // 循环5次
        // child
        while (1) {
            // 五秒之内运行状态
            printf("我是子进程,我正在运行... Pid: %d\n", getpid());
            sleep(1);
 
            // 五秒之后子进程终止
            cnt--;
            if (cnt == 0) {
                break; 
            }
        }
 
        exit(233);   // 方便辨识,退出码我们设置为233,这是我们的预期结果
    }
    else {
        printf("我是父进程: pid: %d,我将耐心地等待子进程!\n", getpid());
        
        // ***** 使用waitpid进行进程等待
        int status = 0;  // 接收 waitpid 的 status 参数
 
        pid_t ret = waitpid(id, &status, 0);
        if (ret > 0) {   // 等待成功
            printf (
                "等待成功,ret: %d, 我所等待的子进程退出码: %d\n", 
                ret,
                (status>>8)&0xFF
            );
        }
 
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46

status 并不是整体使用的,而是区域性使用的,我们要取其次低八位。我们可以用 位操作 来完成,将 status右移八位再按位与上 0XFF,即 (status>>8)&0xFF ,就可以提取到 status 的次低八位了。

在这里插入图片描述

waitpid 经过系统调用,来读取子进程的pcb(eg. task_st…),这是为什么呢

操作系统不相信任何人,父进程用户无法直接读取子进程的 pcb ,要通过系统调用的接口

在这里插入图片描述

2.初识 core dump(核心转储)

在这里插入图片描述

它是操作系统在进程收到某些信号而终止运行时,将此时进程地址空间的内容以及有关进程状态的其他信息写出的一个磁盘文件。目前只需要知道,该信息是用于调试的。

3.最低七位:提取子进程的退出信号

刚才我们讲的 wait/waitpid 和次低八位的时侯,都是关于进程(exit) 的 正常退出。

如果进程 异常退出 呢?我们来模拟一下进程的异常退出。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/天景科技苑/article/detail/940091
推荐阅读
相关标签