APUE学习笔记——8.3~8.4创建新进程fork()、vfork()

  1. #include <unistd.h>
  2. pid_t fork(void);
  3. Returns: 0 in child, process ID of child in parent,?1 on error

Unix可以使用系统函数fork()创建一个新进程。

fork()执行一次返回两次。

返回值:

0: 
          表示子进程

子进程id: 表示父进程

子进程可以通过getppid()来获取父进程id,所以只需要返回0,表示创建成功即可.而对于父进程来说,他无从得知子进程的id,因此在创建的时候就应该吧子进程的Id号返回给他。

我们知道,每个进程都会涉及到进程控制块、正文段、数据段,三部分内容。

进程控制块是每个进程独有的,这就不用多说。

正文段里面是程序的指令,都是只读的,因此父进程和子进程可以共享这部分内容 。share

数据段:  子进程会拷贝一份父进程的数据段(数据空间、堆、栈)。注意:这里是copy而不是share

由于我们知道,一般创建子进程后,进阶着就是使用exec替换子进程为一个新的程序了,这是父进程的数据段内容就没什么用了。因此,现代系统在实现的时候,采用了写时复制copy-on-write(COW)。该方法就是内核将数据段设置为共享share,但它是只读的,当父进程或者子进程下需要对数据进行修改时,就自己copy一个副本。

    Example

  1. #include "apue.h"
  2. #include "myerr.h"
  3. int globvar=6;/*external variable in initialized data */
  4. char buf[] = "a write to stdout\n";
  5. int
  6. main(void)
  7. {
  8. int var; /* automatic variable on the stack */
  9. pid_t pid;
  10. var = 88;
  11. if (write(STDOUT_FILENO, buf, sizeof(buf)-1) != sizeof(buf)-1)
  12. err_sys("write error");
  13. printf("before fork\n"); /* we don’t flush stdout */
  14. if ((pid = fork()) < 0) {
  15. err_sys("fork error");
  16. }else if (pid == 0) { /* child */
  17. globvar++; /* modify variables */
  18. var++;
  19. }else {
  20. sleep(2); /* parent */
  21. }
  22. printf("pid = %ld, glob = %d, var = %d\n", (long)getpid(), globvar, var);
  23. exit(0);
  24. }

执行结果:

  1. [email protected]:~/Windeal/apue$ ./exe
  2. a write to stdout
  3. before fork
  4. pid = 4523, glob = 7, var = 89
  5. pid = 4522, glob = 6, var = 88
  6. [email protected]:~/Windeal/apue$

在这个例子中,我们在子进程中对globvar和var都进行自加,然后又在父进程中sleep(2),使得子进程先执行。

最终结果,父进程的数据都没变,子进程globvar和var都变成了新的值。

从例子中可以看出,正文段是共享的,都使用了printf语句(你要说是copy,我就不跟你辩了。。。)

vfork()

功能与fork()基本相似。

不同点:

vfork保证子进程先执行,也就是子进程执行了exec程序或者exit后才执行fork()。如果子进程中有依赖父进程的下一步动作才能执行的部分,可能会导致死锁。

vfork创建的子进程会共享父进程的数据段。也就是说它会改变父进程的数据。

  1. #include "apue.h"
  2. #include "myerr.h"
  3. int globvar=6;/*external variable in initialized data */
  4. int
  5. main(void)
  6. {
  7. int var; /* automatic variable on the stack */
  8. pid_t pid;
  9. var = 88;
  10. printf("before vfork\n"); /* we don’t flush stdio */
  11. if ((pid = vfork()) < 0) {
  12. err_sys("vfork error");
  13. }else if (pid == 0) { /* child */
  14. globvar++; /* modify parent’s variables */
  15. var++;
  16. _exit(0); /* child terminates */
  17. }
  18. /* parent continues here */
  19. printf("pid = %ld, glob = %d, var = %d\n", (long)getpid(), globvar, var);
  20. exit(0);
  21. }
  22. ~

执行结果:

  1. [email protected]:~/Windeal/apue$ ./exe
  2. before vfork
  3. pid = 6298, glob = 7, var = 89
  4. [email protected]:~/Windeal/apue$

可以看到父进程globvar和var被子进程改变了。

vfork()被一些版本视为过时的接口,一般不使用。所以不必过多研究,多用fork()来创建新进程即可。

时间: 2024-07-30 00:46:40

APUE学习笔记——8.3~8.4创建新进程fork()、vfork()的相关文章

jQuery学习笔记之DOM树、创建新节点、append方法

DOM树. 创建新节点.创建元素节点和文本节点. 创建元素节点/文本节点/属性节点 节点内部插入元素append方法 节点内部插入元素prepend方法 节点外部插入元素after方法 节点外部插入元素before方法 DOM树 创建div元素节点 创建元素节点和文本节点 创建元素节点.文本节点.属性节点 append方法 prepend方法 after方法 before方法

APUE 学习笔记(六) 进程控制

1. fork 创建新进程 fork创建的新进程称为子进程,fork函数调用一次,返回两次. 两次返回的唯一区别就是子进程的返回值是0,而父进程的返回值是新子进程的进程ID 在fork之后是父进程先执行还是子进程先执行是不确定的,这取决于内核的调度算法 fork的一个特性就是父进程的所有打开文件描述符都被复制到子进程中,父子进程的每个相同的打开描述符共享一个文件表项 在fork之后处理文件描述符有两种常见情况: (1)父进程等待子进程完成.在这种情况下,父进程无需对其描述符做任何处理,因为子进程

APUE学习笔记:第九章 进程关系

9.1 引言 本章将更详尽地说明进程组以及POSIX.1引入的会话的概念.还将介绍登陆shell(登录时所调用的)和所有从登陆shell启动的进程之间的关系. 9.1 终端登陆 系统管理员创建通常名为/etc/ttys的文件,其中每个终端设备都有一行,每一行说明设备名传递给getty程序的参数.当系统自举时,内核创建进程ID为1的进程,依旧是init进程.init进程使系统进入多用户状态.init进程读文件/etc/ttys,对每一个允许登陆的终端设备,init调用一次fork,所生成的子进程则

APUE学习笔记:第四章 文件和目录

4.1 引言 本章将描述文件的特征和文件的性质 4.2 stat.fstat和lstat函数 #include<sys/stat.h> int stat(const char *restrict pathname,struct stat *restrict buf); int fstat(int filedes,struct stat *buf) int lstat(const char *restrict pathname,struct stat *restrict buf); 三个函数的返

APUE 学习笔记(十) 高级I/O

1. Unix IPC(InterProcess Communication) 同一主机的各个进程间的IPC:管道.FIFO.消息队列.信号量.共享存储器 不同主机上的各个进程间IPC:socket套接字 2. 管道 管道进行IPC有两个局限: (1) 半双工,即数据只能在一个方向上流动 (2) 只能在具有公共祖先的进程之间使用.通常,一个管道由一个进程创建,然后该进程调用fork,此后 父子进程之间可以使用该管道 fstat函数对管道的每一端都返回一个FIFO类型的文件描述符,可以用S_ISF

APUE学习笔记:第一章 UNUX基础知识

1.2 UNIX体系结构 从严格意义上,可将操作系统定义为一种软件(内核),它控制计算机硬件资源,提供程序运行环境.内核的接口被称为系统调用.公用函数库构建在系统调用接口之上,应用软件即可使用公用函数库,也可使用系统调用.shell是一种特殊的应用程序,它为运行其他应用程序提供了一个接口 从广义上,操作系统包括了内核和一些其他软件,这些软件使得计算机能够发挥作用,并给予计算机以独有的特性(软件包括系统实用程序,应用软件,shell以及公用函数库等) 1.3  shell shell是一个命令行解

APUE学习笔记:第三章 文件I/O

3.1 引言 术语不带缓冲指的是每个read和write都调用内核中的一个系统调用.这些不带缓冲的I/O函数不是ISO C的组成部分,但是,它们是POSIX.1和Single UNIX Specification的组成部分 3.2 文件描述符 UNIX系统shell使用文件描述符0与进程的标准输入相关联.文件描述符1与标准输出相关联.文件描述符2与标准出错输出相关联. 在依从POSIX的应用程序中,幻数0.1.2应当替换成符号常量STDIN_FILENO,STDOUT_FILENO和STDERR

APUE学习笔记:第二章 UNIX标准化及实现

2.2UNIX标准化 2.2.1 ISO C 国际标准化组织(International Organization for Standardization,ISO) 国际电子技术委员会(International Electrotechnical Commission,IEC) ISO C标准的意图是提供C程序的可移植性,使其能适合于大量不同的操作系统,而不只是UNIX系统.此标准不仅定义了C程序设计语言的语法和语义,还定义了其标准库.因为所有现今的UNIX系统都提供C标准中定义的库例程,所以该

APUE学习笔记:第八章 进程控制

8.1 引言 本章介绍UNIX的进程控制,包括创建新进程.执行程序和进程终止.还将说明进程属性的各种ID-----实际.有效和保存的用户和组ID,以及他们如何受到进程控制原语的影响.本章还包括了解释器文件和system函数.本章最后讲述大多数UNIX系统所提供的进程会计机制.这种机制使我们能够从另一个角度了解进程的控制功能. 8.2 进程标识符 每个进程都有一个非负整型表示的惟一进程ID.因为进程标识符是惟一的,常将其用作其他标识符的一部分以保证其惟一性.虽然是惟一的,但是进程ID可以重用.(大