操作系统—进程等待

进程等待的基础概念

进程等待就是为了同步父进程和子进程,如把运算放到子进程,赋值放到父进程,可能需要让父进程等待子进程运算结束.一个进程
在终止时会关闭所有的文件描述符,释放在用户空间分配的内存,但他的PCB还保留着,内核在其中保存了一些信息:如果是正常终
止则保存着退出状态,如果是异常退出则保存着导致该进程终止的信号是哪个. 这个进程的父进程可以调用wait或waitpid获取这
些信息,然后彻底消除掉这个进程。我们知道一个进程的退出状态可以在shall中用特殊变量 $?查看,因为shell是它的父进程,当它终止时
Shell调用wait或waitpid得到它的退出状态同时彻底清除这个进程。


当一个进程正常或异常终止时,内核就向父进程发送一个SIGCHLD信号。因为子进程终止是一个异步时间,所以发生这种信号发生
也是内核向父进程发的异步通知。父进程可以选择忽略该信号,或者提供一个该信号发生时既被调用执行的函数。对于这种信号的系
统默认 动作是忽略它。 而父进程如果需要处理掉子进程就要调用wait和waitpid命令.

进程的三种基本状态

进程在运行中不断地改变其运行状态。通常,一个运行进程必须具有以下三种基本状态。

  • 就绪状态:当进程已分配到除CPU以外的所有必要的资源,只要获得处理机便可立即执行,这时的进程状态称为就绪状态。

  • 执行状态:当进程已获得处理机,其程序正在处理机上执行,此时的进程状态称为执行状态。

  • 阻塞状态:正在执行的进程,由于等待某个事件发生而无法执行时,便放弃处理机而处于阻塞状态。引起进程阻塞的事件可有多
    种,例如,等待I/O完成、申请缓冲区不能满足、等待信件(信号)等。

父进程调用wait和waitpid函数后

如果其所有子进程都还在运行,则阻塞.

如果一个子进程已终止,正等待父进程获取其终止状态,则取得该子进程的终止态立即返回.

如果它没有任何子进程,则立即出错返回.
wait/waitpid函数
头文件:#include<sys/tpes.h>
        #include<sys/wait.h>


wait函数:pid_t wait(int* status)

返回值: 成功返回被等待进程pid,失败返回-1.

参数:输出型参数,获取子进程退出的状态不关心设置空.如果进程由于接收到SIGCHLD而调用wait,则会期望wait会立即返回.但如果

在任意时刻调用wait,则进程可能阻塞.在一个子进程终止前,wait使其调用者阻塞,而waitpid有一个选项,可使调用者不阻塞.如果

status不是一个空指针,则终止进程的终止状态就存放它所指的单元内。 如果不关心终止状态,则可将该参数设为空指针.

waitpid函数:pid_t waitpid(pid_t pid,int *status,int options);


返回值:

1当正常返回时waitpid返回手机的子进程的进程ID

2.如果设置了选项WNOHANG,而调用中waitpid发现没有退出的子进程可手机,贼返回0.

3.如果调用出错返回-1

4.当pid所指示的子进程不存在,或此进程存在,但不是调用进程的子进程waitpid就会出错返回,这是errno被设置为ECHILD参数:
  • 1.pid
    pid = -1,等待任意个子进程
    pid > 0,等待其进程ID与PID相等的子进程
    pid = 0 等待其组ID等于调用进程组ID的任意意个子进程
    pid < -1 等待其组ID等于PID绝对值的任意子进程

  • 2.status:
    WIFEXITED: 若为正常终止子进程的方法返回状态贼为真.
    WEXITSTATUS:若WIFEXITED,提取子进程的退出码.

  • 3.options
    WNOHANG:若pid指定的子进程还没有结束,则waitpid()函数返回0,不予以等待
    若正常结束,则返回该子进程ID.(这里就是我上面说的waitpid的特殊选项)

相关代码:

阻塞等待

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/wait.h>

int main()
{
    pid_t pid;
    pid = fork();
    if(pid < 0)
    {
        printf("%s fork error\n",__FUNCTION__);
        return 1;
    }
    else if(pid == 0)
    {
        //子进程
        printf("this is child,pid is:%d\n",getpid());
        sleep(5);
        exit(257);
    }
    else
    {
        int status = 0;
        pid_t ret = waitpid(-1,&status,0);// wait 5s
        printf("this is test for wait\n");
        if(WIFEXITED(status)&&ret == pid)
            printf("wait child 5s success,child return num is:%d\n",WEXITSTATUS(status));
        else
        {
            printf("wait child failed,return \n");
            return 1;
        }
    }
}

非阻塞等待

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/wait.h>

int main()
{
    pid_t pid;
    pid = fork();
    if(pid < 0)
    {
        printf("%sfork error\n",__FUNCTION__);
        return 1;
    }
    else if(pid == 0)
    {
        //child
        printf("child is run,pid is: %d\n",getpid());
        sleep(5);
        exit(1);
    }
    else
    {
        int status = 0;
        pid_t ret = 0;
        do
        {
            ret = waitpid(-1,&status,WNOHANG);
            printf("father do other thing\n");
            if(ret == 0)
                printf("child is runing\n");
            sleep(1);
        }while(ret == 0);
        if(WIFEXITED(status)&& ret == pid)
            printf("wait child 5s success,child return cod is:%d\n",WEXITSTATUS(status));
        else{
            printf("wait child failed,return\n");
            return 1;
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_40840459/article/details/81050180