转自  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. java中String字符串

    一.定义String字符串 String字符串和char字符不同,char使用单引号,只能表示一个字符,字符串就是一段文本.String是个类.这个类使用final修饰,所以这个类是不可以继承扩充和修 ...

  2. Python3.x--33个保留字

    查询方法也在下图:

  3. 原生js实现模块来回拖拽效果

    代码比较冗余,还没来得及做整理,往见谅. 主要用到的 JS 事件有: onmousedown:鼠标点下事件 onmousemove:鼠标移动事件 onmouseup:鼠标放开事件 具体代码如下: &l ...

  4. 使用input的file进行上传进行预览

    在使用file上传文件的时候,想到了图片预览的功能,然后查询了一些资料,一种是需要后端配合,将数据变成base64或者buff等数据传给后端然后调取接口进行显示,但是这种需要后端的配合和网络请求,感觉 ...

  5. SimHash算法--文章相似度匹配

    SimHash原理 1.SimHash背景 SimHash算法来自于 GoogleMoses Charikar发表的一篇论文"detecting near-duplicates for we ...

  6. ECharts堆叠柱状图label显示总和

    Echarts本身没提供现成的解决方案. option = { title: { text: '分类销量' }, legend: { y: "bottom", data: ['百货 ...

  7. Vue – 基础学习(3):$forceUpdate()和$nextTick()的区别

    Vue – 基础学习(3):$forceUpdate()和$nextTick()的区别

  8. android解析xml (pull)

    1. xml <persons> <person id="18"> <name>furong</name> <age>2 ...

  9. Request和Response。

    复习点:1.重定向问题  2.输出字符串到浏览器.3.文件下载需求:1. 页面显示超链接2. 点击超链接后弹出下载提示框3. 完成图片文件下载 Request和Response Request: 1. ...

  10. JDBC连接时出现的两个错误

    这两个错误都是因为版本的更新导致的: 错误代码: package FirstTest; import java.sql.*; public class FirstJDBC { public stati ...