fork

我们可以通过调用fork创建一个新进程。这个系统调用复制当前进程,在进程表中创建一个新的表项,新表项中的许多属性与当前进程是相同的。新进程几乎与原进程一模一样,执行的代码也完全相同,但新进程有自己的数据空间、环境和文件描述符。fork和exec函数结合在一起使用就是创建新进程所需要的一切了。

fork之后,子进程是父进程的副本。子进程将获得父进程的数据空间、堆和栈的副本。父子进程不共享这些存储空间部分。父子进程共享正文段。

#include <unistd.h>
pid_t fork(void);

在父进程中的fork调用返回的是新的子进程的进程号PID(这个PID并不是父进程的PID,而是新建的子进程的PID)。新进程将继续执行,就像原进程一样,不同之处在于,子进程中的fork调用返回的是0。父子进程可以通过这一点来判断究竟谁是父进程,谁是子进程。如果fork失败,它将返回-1。失败通常是因为父进程所拥有的子进程数目超过了规定的限制(CHILD_MAX),此时errno将被设为EAGAIN。如果是因为进程表里没有足够的空间用于创建新的表单或虚拟内存不足,errno变量将被设为ENOMEM。
也就是说如果fork返回-1,表示进程创建失败;返回0,表示当前进程为子进程;返回其他值表示当前进程为父进程,并且这个值是子进程的PID。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>int main()
{write(STDOUT_FILENO, "write\n", 6);printf("before fork\n");pid_t pid = fork();if (pid == -1){perror("fork error");exit(1);}else if (pid == 0){//printf("This is child process, pid is %d\n", getpid());}else{//printf("This is parent process, pid is %d, child pid is %d\n", getpid(), pid);wait(NULL);}printf("atfer fork\n");return 0;
}

./a.out输出

write
before fork
atfer fork
atfer fork

./a.out > tmp.out;cat tmp.out输出

write
before fork
atfer fork
before fork(多了一句)
atfer fork

因为write系统调用是不带缓冲的,而标准IO库是带缓冲的。

如果标准输出连接到终端设备,则它是行缓冲,否则就是全缓冲。

首先调用write,数据直接写到标准输出。

./a.out的方式,此时标准输出为终端,那么就是行缓冲,遇到换行符输出并冲洗缓冲区,然后fork,此时缓冲区已经没数据了,所以输出一次before fork。

./a.out >tmp.out,此时标准输出为文件,是全缓冲,当缓冲区满了才会冲洗缓冲区,fork的时候缓冲区是有内容的,当进程终止时,会冲洗缓冲区。

wait

当用fork启动一个子进程时,子进程就有了它自己的生命周期并将独立运行。我们可以通过在父进程中调用wait函数让父进程等待子进程的结束。

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

wait系统调用将暂停父进程直到它的子进程结束为止。调用成功返回wait子进程的PID,它通常是已经结束运行的子进程的PID。状态信息允许父进程了解子进程的退出状态,即子进程的main函数返回的值或子进程中exit函数的退出码。如果status不是空指针,状态信息将被写入它所指向的位置。

如果调用进程没有子进程,调用就会失败,此时wait返回-1,同时errno被置为ECHILD。

如果参数status的值不是NULL,wait就会把子进程退出时的状态取出并存入其中,这是一个整数值(int),指出了子进程是正常退出还是被非正常结束的(一个进程也可以被其他进程用信号结束,我们将在以后的文章中介绍),以及正常结束时的返回值,或被哪一个信号结束的等信息。由于这些信息被存放在一个整数的不同二进制位中,所以用常规的方法读取会非常麻烦,人们就设计了一套专门的宏(macro)来完成这项工作。

WIFEXITED(status) 这个宏用来指出子进程是否为正常退出的,如果是,它会返回一个非零值。

WEXITSTATUS(status) 当WIFEXITED返回非零值时,我们可以用这个宏来提取子进程的返回值,如果子进程调用exit(5)(或者return 5或者_exit(5))退出,WEXITSTATUS(status) 就会返回5;如果子进程调用exit(7),WEXITSTATUS(status)就会返回7。请注意,如果进程不是正常退出的,也就是说, WIFEXITED返回0,这个值就毫无意义。

WIFSIGNALED(status) 如果子进程是因为一个未捕获的信号而终止,则此宏值为非零值。

WTERMSIG(status) 如果WIFSIGNALED非零,返回子进程因信号而中止的信号代码。

WIFSTOPPED(status) 如果子进程意外终止,它就取一个非零值。

WSTOPSIG(status) 如果WIFSTOPPED非零,返回一个信号代码。

#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#include <stdlib.h>int main()
{pid_t pid = fork();if (pid == -1){perror("fork error");exit(1);}else if (pid == 0){printf("This is child process, pid is %d\n", getpid());sleep(3);exit(5); // or return 5 or _exit(5);}else{printf("This is parent process, pid is %d, child pid is %d\n", getpid(), pid);int status;printf("wait child pid:%d\n", wait(&status));if (WIFEXITED(status)){printf("successful, exit code is %d\n", WEXITSTATUS(status));}}return 0;
}

This is parent process, pid is 733, child pid is 734
This is child process, pid is 734
// sleep了3秒
wait child pid:734
successful, exit code is 5

僵尸进程

用fork来创建进程确实很有用,但你必须清楚子进程的运行情况。子进程终止时,它与父进程之间的关联还会保持,直到父进程也正常终止或父进程调用wait才告结束。因此,进程表中代表子进程的表项不会立刻释放。虽然子进程已经不再运行,但它仍然存在于系统中,因为它的退出码还需要保存起来,以备父进程今后的wait调用使用。这时它将成为一个死(defunct)进程或僵尸(zombie)进程。(子进程早于父进程结束,并且父进程没有调用wait来回收子进程就会造成僵尸进程)

waitpid

waitpid函数可以用来等待某个特定进程的结束。

#include<sys/types.h>
#include<sys/wait.h>
pid_t waitpid(pid_t pid,int * status,int options);

pid参数指定需要等待的子进程的PID。如果它的值为-1,waitpid将返回任一子进程的信息。与wait一样,如果status不是空指针,waitpid将把状态信息写到它所指向的位置。option参数可用来改变waitpid的行为,其中最有用的一个选项是WNOHANG,它的作用是防止waitpid调用将调用者的执行挂起。你可以用这个选项来查找是否有子进程已经结束,如果没有,程序将继续执行。其他的选项和wait调用的选项相同。 因此,如果想让父进程周期性地检查某个特定的子进程是否已终止,就可以使用如下的调用方式:

waitpid(child_pid, (int *)0, WNOHANG);

如果子进程没有结束或意外终止,它就返回0,否则返回child_pid。如果waitpid失败,它将返回-1并设置errno。失败的情况包括:没有子进程(errno设置为ECHILD)、调用被某个信号中断(EINTR)或选项参数无效(EINVAL)

Linux进程相关,fork,wait,waitpid,WIFEXITED相关推荐

  1. linux进程(fork,waitpid)

    对于进程的一生可以用一些形象的比喻作一个小小的总结: 随着一句fork,一个新进程呱呱落地,但它这时只是老进程的一个克隆. 然后随着exec,新进程脱胎换骨,离家独立,开始了为人民服务的职业生涯. 人 ...

  2. Linux进程创建fork、进程退出exit()、进程等待waitpid()

    虽然通过标题,我们就轻易的知道了这三个函数的作用,可是,你真的了解这几个函数码?下面让我们来看看这三个函数到底有什么! 一.进程创建fork() 首先,我们来看一看fork()的函数声明: #incl ...

  3. linux进程管理fork,Linux -- 进程管理之 fork() 函数

    一个进程调用fork()函数后,系统先给新的进程分配资源,例如存储数据和代码的空间.然后把原来的进程的所有值都复制到新的新进程中,只有少数值与原来的进程的值不同.相当于克隆了一个自己. Test1 f ...

  4. linux 进程等待 wait 、 waitpid

    waitpid() 与 wait() 功能相似,都是用户主进程等待子进程结束或中断. 可用于进程之间的同步 wait 函数原型 pid_t wait(int *status); 函数说明 wait() ...

  5. linux 进程wait,linux 进程等待 wait 、 waitpid(示例代码)

    waitpid() 与 wait() 功能相似,都是用户主进程等待子进程结束或中断. 可用于进程之间的同步 wait 函数原型 pid_t wait(int *status); 函数说明 wait() ...

  6. 【SRE笔记 2022.9.7 linux进程相关命令及源码包安装】

    SRE笔记 2022.9.7 源码包 定义 源码包安装 优缺点 优点 缺点 获取 安装 C语言和开发 nginx安装示例 基础环境准备 gcc make wget 下载源码包 解压源码包,进入目录 ( ...

  7. linux 进程sockfd fork,Linux下多进程服务端客户端模型一(单进程与多进程模型)...

    本文将会简单介绍Linux下如何利用C库函数与系统调用编写一个完整的.初级可用的C-S模型. 一.基本模型: 1.1   首先服务器调用socket()函数建立一个套接字,然后bind()端口,开始l ...

  8. Linux进程相关命令

    一.ps命令 Linux中的ps命令是Process Status的缩写.ps命令用来列出系统中当前运行的那些进程, ps命令时列出当前进程的快照,想要动态的显示进程的相关信息,需要使用top命令 ① ...

  9. linux创建多个子进程,[Linux进程]使用fork函数创建多个子进程

    #include #include int main (void) { pid_t pid1,pid2;   //进程标识符 pid1 = fork();      //创建一个新的进程 if(pid ...

最新文章

  1. TVM性能评估分析(七)
  2. 企业管理软件的需求描述方法
  3. PostgreSQL操作问题(转载)
  4. [androd] android的在线源码网站,各个版本都有(目前已到俺android 4.2,但不包含kernel部分的代码)
  5. 在hadoop/hbase等代码中kinit
  6. zencart产品批量维护系统--视频教程
  7. ie6 z-index bug
  8. DFS和BFS总结和代码演示(详解)
  9. 探讨一下,数据库里账号的密码,怎样存放更加安全?
  10. 错失双节福利?这12本新书投送了解一下
  11. html中使用style设置背景
  12. 光纤测试、OTDR使用经验、FS530OTDR使用经验
  13. ios safari 模拟器_iOS 模拟器调试大法了解一下?
  14. libtorrent源码分析(二)VS上libtorrent编译总结
  15. 居家办公提高工作效率的八点建议
  16. 最新国家行政区划数据下载(截止2017年10月31日)目前2019.1.21仍为最新数据
  17. java.lang.NoClassDefFoundError: org/jdom2/Content
  18. idea鼠标控制放大缩小的操作
  19. java计算机毕业设计基于安卓Android/微信小程序的大学生签到管理系统APP
  20. Java poi XWPFDocument 操作2007Word,实现参数替换、新增 插入 替换 表格数据、创建饼状图、柱形图、折线图

热门文章

  1. 启动未来城市数据中心的设想
  2. Unity 图片渐变色的实现
  3. SetWindowPos
  4. CreateDirectory 和 PathFileExists 为什么调用dllhost.exe进程
  5. Hibernate之Query接口的uniqueResult 方法
  6. 2006重大太空发现
  7. Elasticsearch的介绍 以及使用python操作es详细步骤
  8. 战意亚服登录显示服务器已满,战意公测第3天:服务器爆满、好评如潮、人气主播走上人生巅峰!...
  9. 把 Linux装进u 盘,用UNetbootin轻松把Linux操作系统装进U盘
  10. 无法定位序数9828于动态链接库或者exe