转自  http://blog.csdn.net/todd911/article/details/14062103

1.fork函数

一个现有的进程可以调用fork函数创建一个新的子进程。

#include <unitsd.h>
pid_t fork(void);    //子进程返回0,父进程返回子进程ID,出错返回-1。

关于fork函数的常规用法这边不说了,下面说明下父子进程的文件共享。子进程是父进程的副本,例如,子进程获得父进程数据空间、栈和堆的副本,这是子进程所拥有的副本,父子进程并不共享这些存储空间部分。由于在fork之后经常跟随着exec,所以现在的很多实现并不执行一个父进程数据段、栈和堆的完全复制,作为替代,使用了写时复制(copy on write,COW)技术。

一个进程具有三个不同的打开文件,它们是标准输入,标准输出和标准出错,从fork返回时,我们有了下面的结构。

这种共享文件的方式使父子进程对同一文件使用了一个文件偏移量,如果父子进程都向标准输出进行写操作,如果父进程的标准输出已经重定向,那么子进程写到标准输出时,它将更新与父进程共享的该文件的偏移量。比如当父进程等待子进程时,子进程写到标准输出,而在子进程终止后,父进程也写到标准输出,并且其输出会添加在子进程所写数据之后,如果父子进程不共享同一文件偏移量,这种形式的交互很难实现。

除了打开文件之外,父进程的很多其他属性也由子进程继承,包括:

  • 实际用户ID,实际组ID,有效用户ID,有效组ID。
  • 附加组ID。
  • 进程组ID。
  • session ID。
  • 控制终端。
  • 设置用户ID标志和设置组ID标志。
  • 当前工作目录。
  • 根目录。
  • 文件模式创建屏蔽字。
  • 信号屏蔽和安排。
  • 针对任意开打文件描述符的在执行时关闭(close-on-exec)标志。
  • 环境。
  • 连接的共享存储段。
  • 资源映射。
  • 资源限制。
父子进程的区别是:
  • fork返回值。
  • 进程ID不同。
  • 两个进程具有不同的父进程ID。
  • 子进程的tms_utime,tms_stime,tms_cutime以及tms_ustime均设置为0.
  • 父进程设置的文件锁不会被子进程继承。
  • 子进程的未处理alarm被清除。
  • 子进程的未处理信号设置为空集。
实践:
#include <stdio.h>
#include <unistd.h>
int g_a = ;
int main(void){
int l_b = ;
pid_t p;
if((p = fork()) < ){
perror("fork");
}else if(p == ){
g_a++;
l_b++;
}
printf("pid = %d,g_a = %d,l_b = %d\n", getpid(), g_a, l_b);
return ;
}
运行结果:
[yan@yanPC apue]$ ./a.out
pid = 15869,g_a = 2,l_b = 2
pid = 15868,g_a = 1,l_b = 1
[yan@yanPC apue]$ ./a.out
pid = 15870,g_a = 1,l_b = 1
pid = 15871,g_a = 2,l_b = 2
从运行结果来看,子进程的变量进行了改变,而父进程中的变量没有,因为他们是不同的地址空间,不会相互影响。二是父子进程到底哪个先运行是随机的。 

2.vfork函数

vfork函数的调用序列和返回值与fork相同,但是两者的语义不同。
1.vfork和fork都是创建一个子进程,但是它并不将父进程的地址空间完全复制到子进程中,因为子进程会立即调用exec(或exit),于是也就不会存访该地址空间,相反在子进程调用exec或exit之前,它在父进程的空间中运行。这种优化工作方式在某些unix的页虚拟存储器实现中提高了效率。
2.vfork保证子进程先运行,在它调用exec或exit之后父进程才可能被调度运行。
实践:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h> int g_a = ; int main(void){
int l_b = ;
pid_t p;
if((p = vfork()) < ){
perror("fork");
}else if(p == ){
g_a++;
l_b++;
}
printf("ppid = %d,pid = %d,g_a = %d,l_b = %d\n", getppid(), getpid(), g_a, l_b);
return ;
}
运行结果:
[yan@yanPC apue]$ ./a.out
ppid = 16090,pid = 16091,g_a = 2,l_b = 2
ppid = 15773,pid = 16090,g_a = 2,l_b = 3908224
Segmentation fault
出现了段错误,因为父子程序在同一内存空间运行,子程序结束后肯定会释放相关的内存,此时父进程再去访问相关的内存,则出现未知的段错误。将程序修改为如下:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h> int g_a = ; int main(void){
int l_b = ;
pid_t p;
if((p = vfork()) < ){
perror("fork");
}else if(p == ){
g_a++;
l_b++;
_exit();       //为什么现在好了??
}
printf("ppid = %d,pid = %d,g_a = %d,l_b = %d\n", getppid(), getpid(), g_a, l_b);
return ;
}  
运行结果:
ppid = 15773,pid = 16166,g_a = 2,l_b = 2
在子进程中修改的变量在父进程中打印出来也被进行了修改,说明父子进程使用的是同一块内存空间。
在子进程调用了_exit()函数,使子进程退出,但是不关闭标准的IO流等清理操作,如果使用了exit()函数,那么等到父进程执行时可能会出现意料以外的结果。
下面是vfork的一段官方说明:
vfork()  differs from fork(2) in that the parent is suspended until the
       child terminates (either normally, by calling _exit(2), or  abnormally,
       after  delivery  of  a  fatal signal), or it makes a call to execve(2).
       Until that point, the child shares all memory with its parent,  includ‐
       ing  the stack.  The child must not return from the current function or
       call exit(3), but may call _exit(2).

fork,vfork的更多相关文章

  1. UNIX高级环境编程(9)进程控制(Process Control)- fork,vfork,僵尸进程,wait和waitpid

    本章包含内容有: 创建新进程 程序执行(program execution) 进程终止(process termination) 进程的各种ID   1 进程标识符(Process Identifie ...

  2. Linux进程理解与实践(一)基本概念和编程概述(fork,vfork,cow)

    进程 and 程序 什么是程序? 程序是完成特定任务的一系列指令集合. 什么是进程? [1]从用户的角度来看:进程是程序的一次执行过程 [2]从操作系统的核心来看:进程是操作系统分配的内存.CPU时间 ...

  3. linux 进程创建clone、fork与vfork

    目录: 1.clone.fork与vfork介绍 2.fork说明 3.vfork说明 4.clone说明5.fork,vfork,clone的区别 内容: 1.clone.fork与vfork介绍 ...

  4. fork与vfork区别

    1. 地址空间各段拷贝: fork: 内核为子进程生成新的地址空间结构,拷贝父进程的代码段,数据空间,堆,栈到自身的地址空间,但注意:子进程的代码段并不会分配物理空间,而是指向父进程的代码段物理空间, ...

  5. fork()和vfork()的区别(转载)

    fork和vfork 转载 http://coolshell.cn/articles/12103.html 在知乎上,有个人问了这样的一个问题--为什么vfork的子进程里用return,整个程序会挂 ...

  6. c语言exit和return区别,在fork和vfork中使用

    转自c语言exit和return区别,在fork和vfork中使用 exit函数在头文件stdlib.h中. 简述: exit(0):正常运行程序并退出程序: exit(1):非正常运行导致退出程序: ...

  7. 进程控制fork vfork,父子进程,vfork保证子进程先运行

    主要函数: fork 用于创建一个新进程 exit 用于终止进程 exec 用于执行一个程序 wait 将父进程挂起,等待子进程结束 getpid 获取当前进程的进程ID nice 改变进程的优先级 ...

  8. fork()和vfork()的区别,signal函数用法,exec()系列函数的用法小结

    一:fork()和vfork()的区别:    fork()函数可以创建子进程,有两个返回值,即调用一次返回两个值,一个是父进程调用fork()后的返回值,该返回值是刚刚创建的子进程的ID;另一个是子 ...

  9. fork与vfork

    先看一个fork的例子: ; int main(void) { int var, pid; ; ) { printf("vfork error"); exit(-); } ) { ...

随机推荐

  1. SpringBoot中使用@scheduled定时执行任务需要注意的坑

    spring boot: 计划任务@ EnableScheduling和@Scheduled @Scheduled中的参数说明 @Scheduled(fixedRate=2000):上一次开始执行时间 ...

  2. Asp.Net Core中使用GDI+绘图提示gdiplus库找不到的问题

    参考  https://www.cnblogs.com/VirtualMJ/p/9917916.html 文章中   1 2 3 yum install -y epel-release yum mak ...

  3. [個人紀錄] windows form , usercontrol design 模式不見

    windows form 跟 usercontrol 都變成cs檔 無法點擊進入設計模式 <Compile Include="Form1.cs"/> <Compi ...

  4. Web前端推荐学习站点

    http://javascript.ruanyifeng.com/   JavaScript参考标准教程,写的很不错. https://www.xiaohuochai.cc/  小火柴前端站 http ...

  5. elementUI一次请求上传多个文件

    elementui <el-upload                       class="upload-demo"                       ac ...

  6. jQuery基础学习

    一.简介 jQuery是一个快速.简洁的JavaScript框架,是继Prototype之后又一个优秀的JavaScript代码库(或JavaScript框架).jQuery设计的宗旨是“Write ...

  7. 单词diamaund钻石diamaund英文

    Diamond Di"a*mond (?; 277), n. [OE. diamaund, the hardest iron, steel, diamond, Gr. . Perh. the ...

  8. ML-线性 SVM 推导

    Max Margin svm 即Suport Vector Machine, 中文意为:支持向量机. 对于二分类问题, 在样本空间中(即便是多维向量, 在空间中可表示为一个点). svm的核心思想就是 ...

  9. Docker搭建Zentao(禅道)

    禅道搭建方式有很多种,可参考官方文档搭建,这里介绍的是参考官方文档以docker方式搭建. 禅道内部默认会自动安装mysql数据库. 一.下载地址 禅道开源版:   http://dl.cnezsof ...

  10. Prometheus(四):Prometheus+Alertmanager 配置邮件报警

    此处默认已安装Prometheus服务,服务地址:192.168.56.200  一.安装Alertmanager 此处采用源码编译的方式安装.首先下载alertmanager的软件包,下载地址:ht ...