进程终止和等待——exit和wait

进程终止

进程正常退出通过调用exit函数,异常退出通常是ctr+c信号终止。

exit函数其实最终要调用_exit函数完成进程终止,其步骤是:

  1. 执行atexit 或 on_exit定义的清理函数
  2. 关闭所有打开的流,所有缓存数据均被写入
  3. 调用_exit

void _exit(int status); status定义了进程终止状态,需要注意status的范围是0~255,即低八位可以被父进程获取到。

return n 相当于 exit(n)。将函数退出状态当作返回值。

atexit函数的作用是在函数退出时执行它的参数函数。

void funA()
{
    printf("funA\n");
}
int main()
{
    atexit(funA);
    printf("hello");
    _exit(0);
}

没有任何输出,说明进程直接被终止。

void funA()
{
    printf("hello funA\n");
}

int main(void)
{
    atexit(funA);
    printf("main\n");
    exit(0);
}

main

hello funA

执行结果说明exit函数调用_exit前执行了atexit函数,并且刷新了缓冲区内容。

atexit的原理其实就是在调用时注册回调函数,入栈,在调用exit时出栈并执行回调函数。

#include <stdio.h>
#include <stdlib.h>
typedef struct Node{

    void (*pfun)(void);
    struct Node *next;
}node;

void at_exit(void (*f)(void), node *pHead){
    node *pnode = malloc(sizeof(node));
    pnode->pfun = f;
    pnode->next = NULL;
    //头插
    pHead->next = pnode;
}

void Exit(node *pHead){
    //出栈
    while(pHead->next){
        pHead->next->pfun();
        pHead->next = pHead->next->next;
    }
}
void funA()
{
    printf("hello funA\n");
}

int main(void)
{
    node Head;
    Head.next = NULL;
    node *pHead = &Head;

    at_exit(funA, pHead);
    printf("main\n");
    Exit(pHead);
}

补充一个函数属性

void test() __attribute__((constructor));   

在声明函数时,可以为函数声明一个属性,例如constructor,在main函数执行前调用。

进程等待

为什么需要进程等待?

  1. 如果子进程退出,父进程不管不顾,子进程变为僵尸进程,造成内存泄露
  2. 父进程需要得到子进程的返回状态

pid_t wait(int *status);

等待成功返回等待进程pid,失败返回-1. status是子进程退出状态,不关心时设为NULL。

waitpid 是wait的升级版

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

pid参数:

  1. pid > 0 等待进程ID和pid相等的子进程
  2. pid = -1 等待任意子进程,和wait等效
  3. pid < -1 等待进程组ID和pid相等的组内任一子进程

options:

WNOHANG ,非阻塞式等待,若子进程没有结束,则不等待,返回0.

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{
    pid_t pid = fork();

    if(pid == 0){
        //子子
        printf("子进程pid: %d\n", getpid());
        pid_t pidChild = fork();
        if(pidChild == 0){
            printf("子子进程pid: %d\n", getpid());
            while(1){
                printf("X");
                fflush(stdout); 
                sleep(1);
            }
        }
        exit(-1);
    }
    else{
        int sta;
        pid_t p = wait(&sta);
        printf("父进程回收的pid = %d, 退出状态 = %d\n", p, (sta>>8)&0xFF);
        while(1){
            printf("O");
            fflush(stdout);     
            sleep(1);
        }
    }                       
}

子进程pid: 15307
父进程回收的pid = 15307, 退出状态 = 255
O子子进程pid: 15308
OXOXOXOXOXOXOXOXOXOXOXOXOXOXOXOXOXOXOXOXOXOXOXOXOXOXOXOXOXOXOXOXOXOXOXOXOXOXOXOXOXOXOXOXOXOXXOXOXOXOXOXOXO^C

输出结果说明:

父进程等待回收了子进程,但是退出状态-1 变为255,说明status只使用int低八位且是unsigned.

然后父进程和子子进程交叉执行。

猜你喜欢

转载自blog.csdn.net/hanzheng6602/article/details/80234496
今日推荐