C语言wait函数和fork使用

目录:
1、wait函数和waitpid函数
1.1、wait和waitpid出现的原因
1.2、wait()和waitpid()函数使用
1.3、wait获取staus后检测处理
2、使用示例
2.1、wait()使用
2.2、waitpid使用


1、wait函数和waitpid函数:

1.1、wait和waitpid出现的原因:

1)、SIGCHLD:

  • 当子进程退出的时候,内核会向父进程发送SIGCHLD信号,子进程的退出是个异步事件(子进程可以在父进程运行的任何时刻终止);
  • 子进程退出时,内核将子进程置为僵尸状态,这个进程成为僵尸进程,它只保留最小的一些内核数据结构,以便父进程查询子进程的退出状态;
  • 父进程查询子进程的退出状态可以用wait/waitpid函数;

1.2、wait()和waitpid()函数使用:

wait函数在默认的如下系统库:

#include <sys/types.h>   
#include <sys/wait.h>
pid_t wait(int *status)

进程一旦调用了wait,就立即阻塞自己,由wait自动分析是否当前进程的某个子进程已经退出,如果让它找到了这样一个已经变成僵尸的子进程,wait就会收集这个子进程的信息,并把它彻底销毁后返回;如果没有找到这样一个子进程,wait就 会一直阻塞在这里,直到有一个出现为止。waitpid()的作用和wait()一样,但它并不一定要等待一个终止的子进程,它还有若干选项,如可提供一个非阻塞版本的wait()功能,也能支持作用控制。
参数status用来保存被收集进程退出时的一些状态,它是一个指向int类型的指针。但如果我们对这个子进程是如何死掉的毫不在意,只想把这个僵尸进程消灭掉,(事实上绝大多数情况下,我们都会这样想),我们就可以设定这个参数为NULL,就象下面这样:

pid = wait(NULL); 

1)、wait()函数:

函数签名: pid_t wait(int *status);
函数传入值:这里的status是一个整型指针,是该子进程退出的状态。若status不为空,则通过它可以获取子进程的结束状态。另外,子进程的结束状态有Linux系统中特定的宏来检测实际的进程返回的值;
函数返回值:成功返回已结束运行的子进程id,失败直接返回-1;

2)、waitpid()函数:

2.1)、函数签名:pid_t waitpid(pid_t pid, int *status, int options);
2.2)、函数入参:

pid:

  • pid>0时,只等待进程ID等于pid的子进程,不管是否已经有其它子进程运行结束退出了,只要指定的子进程还没有结束,waitpid就会一直等下去。
  • pid=-1时,等待任何一个子进程退出,没有任何限制,此时waitpid和wait的作用一模一样。
  • pid=0时,等待同一个进程组中的任何子进程,如果子进程已经加入了别的进程组,waitpid不会对它做任何理睬。
  • pid<-1时,等待一个指定进程组中的任何子进程,这个进程组的ID等于pid的绝对值。

options:
提供了一些额外的选项来控制waitpid,目前在Linux中只支持WNOHANG和WUNTRACED两个选项,这是两个常数,可以用"|"运算符把它们连接起来使用,比如:
ret=waitpid(-1,NULL,WNOHANG | WUNTRACED);
如果我们不想使用它们,也可以把options设为0,如:
ret=waitpid(-1,NULL,0);

  • WNOHANG:若由指定的子进程没有结束,则waitpid()不阻塞而立即返回,此时返回值为0;
  • WUNTRACED:指定的任一子进程已被暂停,且其状态子暂停以来还未报告过,则返回其状态;
2.3)、函数返回值:

1.正常结束返回子进程的id;
2.使用WNOHANG且没有子进程退出返回0;
3.失败返回-1;

1.3、wait获取staus后检测处理:

由于在使用waitpid()函数的时候获取到的进程状态值对其直接输出会与实际返回值不一致,所以需要引用(WIFEXITED|WEXITSTATUS)等宏定义来输出进程实际的状态信息值,宏定义和对应的描述,如下:

1)、WIFEXITED(status): 如果进程子进程正常结束,返回一个非零值;

  • WEXITSTATUS(status):如果WIFEXITED非零,返回子进程退出码。如果子进程调用exit(5)退出,WEXITSTATUS(status)就会返回5;

2)、WIFSIGNALED(status): 子进程因为捕获信号而终止,返回非零值;

  • WTERMSIG(status):如果WIFSIGNALED非零,返回信号代码;

3)、WIFSTOPPED(status): 如果进程被暂停,返回一个非零值;

  • WSTOPSIG(status):如果WIFSTOPPED非零,返回信号代码;

2、使用示例:

2.1、wait()使用:

fork是一个创建新进程的系统调用。当调用 fork 时,它会创建一个与调用进程几乎完全相同的新进程(子进程)。fork 返回两次,一次在父进程中,另一次在子进程中。具体来说,fork 在父进程和子进程中的行为如下:
父进程:调用 fork 后,fork 返回子进程的 PID(正整数)。
子进程:调用 fork 后,fork 返回 0。
因此,fork 可以通过返回值来区分它是在父进程中还是在子进程中运行。

下面的代码流程如下:
1.父进程执行fork()创建一个子进程,fork()返回创建子进程的PID值非0值,进入else判断即父进程执行代码区域调用wait()方法等待子进程结束;
2.同样的代码拷贝到创建的子进程中,在子进程第一次调用fork()时候返回0值然后进去执行子进程执行代码相关逻辑(要是在子进程执行代码区域再次执行fork()那么子进程就会在创建出孙子进程);

void forkUsed(void){
    int pid;
    printf("father progress\n");
    if (0 ==fork()){
        // 子进程执行代码
        printf("father progress forked\n");

    }else{
        // 父进程执行代码
        if (-1 ==(pid=wait(NULL))){
            printf("no child progress,and wait() return -1\n");
        } else{
            printf("wait() return child progress pid:%d\n",pid);
        }
    }

    /*
     * 输出结果为:
     * father progress
     * father progress forked
     * wait() return child progress pid:xxx
     */
}

2.2、waitpid()使用:

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

int main(){
    pid_t pc,pr;
    pc= fork();
    if (pc == 0){
        sleep(5);
        exit(0);
    }else{
        // 循环测试子进程是否退出
        do {
            pr= waitpid(pc,NULL,WNOHANG);
            //若子进程还未退出,则父进程暂停1s
            if (pr ==0){
                printf("The child process has not exited\n");
                sleep(1);
            }
        } while (pr ==0);

        if (pr == pc){
            printf("get child exit code:%d\n",pr);
        } else{
            printf("waitpid error\n");
        }
    }

    /*
     * 输出结果:
     * The child process has not exited
     * The child process has not exited
     * The child process has not exited
     * The child process has not exited
     * The child process has not exited
     * get child exit code:xxx
     * 
     * 子进程暂停5s,而在父进程每隔1s来判断该子进程是否退出,所以这里总共打印5条。
     * 说明waitpid没有阻塞,且指定子进程没有退出返回0,指定进程退出返回其进程ID
     */
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,126评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,254评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,445评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,185评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,178评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,970评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,276评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,927评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,400评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,883评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,997评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,646评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,213评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,204评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,423评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,423评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,722评论 2 345

推荐阅读更多精彩内容