美文网首页
wait() 系统调用

wait() 系统调用

作者: wjundong | 来源:发表于2019-12-04 10:53 被阅读0次

先备知识fork系统调用

对wait()的调用会阻塞调用进程,直到它的一个子进程退出或接收到信号。子进程终止后,父进程继续执行wait()系统调用后面的指令。

子进程可能会由于以下任何原因而终止:

  • 它调用exit();
  • 它从main返回(一个int)。
  • 它接收一个信号(来自OS或另一个进程),该信号的默认操作是终止信号。
图示

在C语言中的用法

#include
#include

// 接受一个参数status并返回终止的子进程的ID
pid_t wait(int *stat_loc);  

如果进程有多个子进程,则在调用wait()后,如果没有子进程终止,则父进程必须处于等待状态。

如果只有一个子进程终止,则返回wait()返回终止的子进程的进程ID。

如果终止了多个子进程,则wait()将获取任意的子进程并返回该子进程的进程ID。

当wait()返回时,可以通过传入的int *status指针我们可以知道进程为什么终止,如果传入NULL,则代表我们不想获取该信息。

如果任何进程没有子进程,则wait()立即返回“-1”。

例子1

:“由于环境问题,此代码不能在简单的IDE中运行,需要使用终端来运行代码”

// 演示wait()工作的C程序
#include<stdio.h> 
#include<stdlib.h> 
#include<sys/wait.h> 
#include<unistd.h> 

int main() 
{ 
    pid_t cpid; 
    if (fork()== 0) 
        exit(0);         /* 子进程终止 */
    else
        cpid = wait(NULL); /* 父进程等待子进程终止 */
    
    printf("Parent pid = %d\n", getpid()); 
    printf("Child pid = %d\n", cpid); 

    return 0; 
} 

输出

Parent pid = 12345678 
Child pid = 89546848 
// 演示wait()工作的C程序
#include<stdio.h> 
#include<sys/wait.h> 
#include<unistd.h> 

int main() 
{ 
    if (fork()== 0) 
        printf("HC: hello from child\n"); 
    else { 
        printf("HP: hello from parent\n"); 
        wait(NULL); 
        printf("CT: child has terminated\n"); 
    }

    printf("Bye\n"); 
    return 0; 
} 

输出

HC: hello from child
Bye
HP: hello from parent
CT: child has terminated
     (或)
HP: hello from parent
HC: hello from child
CT: child has terminated    // 这段没有在 HC 之前打印,这是wait函数的原因
Bye

子进程的状态信息(status)
wait()报告的关于孩子的状态信息不仅仅是孩子的退出状态,它还包括:

  • 正常/异常终止
  • 终止原因
  • 退出状态

要查找有关状态的信息,我们可以使用WIF…相关的宏

编号 调用 说明
1 WIFEXITED(status) 子进程正常退出
. WEXITSTATUS(status) 当子进程退出时返回代码
2 WIFSIGNALED(status) 由于未捕获信号,子进程退出
. WTERMSIG(status) 给出终止信号的编号
3 WIFSTOPPED(status) 子进程项停止
. WSTOPSIG(status) 给出停止信号的编号
/* 如果要打印有关信号的信息 */
void psignal(unsigned sig,const char*s)

例子2

检查以下程序的输出

// C程序演示如何使用wait()返回的status状态信息 
#include<stdio.h> 
#include<stdlib.h> 
#include<sys/wait.h> 
#include<unistd.h> 

void waitexample() 
{ 
    int stat; 

    if (fork() == 0) 
        // 子进程自己退出,退出返回值为1
        // 此状态信息 1 由WEXITSTATUS报告
        exit(1); 
    else
        wait(&stat); 

    // 如果是自愿退出
    if (WIFEXITED(stat)) 
        printf("Exit status: %d\n", WEXITSTATUS(stat));
    // 如果是收到终止信号退出的
    else if (WIFSIGNALED(stat)) 
        psignal(WTERMSIG(stat), "Exit signal"); 
} 


// 主程序
int main() 
{ 
    waitexample(); 
    return 0; 
} 

输出

Exit status: 1

例子3

我们知道如果多个子进程被终止,则wait()将获取任意的子进程,但如果我们想等待特定子进程终止,则使用waitpid()函数

// waitpid在C语言中的用法
pid_t waitpid (pit_t child_pid, int *status, int options);

options 如果是0表示没有选项,则父节点必须等待终止子节点。

options 如果是WNOHANG表示父进程不等待,如果子进程没有终止,则也往下执行。

如果child_pid为-1,则表示任意子进程,此处waitpid()的工作与wait()的工作相同。

waitpid()的返回值

  • 如果options为0且子进程退出,则返回子进程的PID
  • 如果options为WNOHANG选项且子进程未退出,也返回子进程的PID
// C程序演示如何使用waitpid()函数
#include<stdio.h> 
#include<stdlib.h> 
#include<sys/wait.h> 
#include<unistd.h> 

void waitexample() 
{ 
    int i, stat; 
    pid_t pid[5]; 
    // 由主进程创建了5个子进程
    for (i=0; i<5; i++)  { 
        if ((pid[i] = fork()) == 0) { 
            sleep(1); 
            exit(100 + i); 
        } 
    }

    // 使用waitpid()并打印子进程的退出状态
    for (i=0; i<5; i++)  { 
        // options为0,阻塞等待
        pid_t cpid = waitpid(pid[i], &stat, 0); 
        // 如果是子进程是调用exit()退出的
        if (WIFEXITED(stat)) 
            printf("Child %d terminated with status: %d\n", 
                cpid, WEXITSTATUS(stat)); 
    } 
} 

int main() 
{ 
    waitexample(); 
    return 0; 
} 

输出

Child 50 terminated with status: 100
Child 51 terminated with status: 101
Child 52 terminated with status: 102
Child 53 terminated with status: 103
Child 54 terminated with status: 104

这个程序依次创建了5个子进程,5个进程都是由主进程创建,因为if ((pid[i] = fork()) == 0)使得子进程刚出生就接着sleep()+exit(),子进程没有创建自己的子进程的机会。最后主进程根据pid数组,获取每个子进程返回的状态。

相关文章

网友评论

      本文标题:wait() 系统调用

      本文链接:https://www.haomeiwen.com/subject/nqmkgctx.html