n返回值:
fork函数调用一次,但是返回两次:在子进程中返回0,在父进程中返回子进程ID,出错返回-1。通过返回值,可以确定是在父进程还是子进程中。
n子进程和父进程继续执行fork调用之后的指令。
子进程是父进程的副本:
1.子进程获得父进程数据空间、堆和栈的副本;父子进程并不共享这些存储空间。
2.父子进程共享正文段(只读的);
3.为了提高效率,fork后并不立即复制父进程空间,采用了COW(Copy-On-Write);当父子进程任意之一,要修改数据段、堆、栈时,进行复制操作,但仅复制修改区域
看一个程序:
#include<iostream>
#include<unistd.h>
#include<stdio.h> using namespace std; int glob = 6;
char buf[] = "a write to stdout\n"; int main(void)
{
int var;
pid_t pid; var = 88; if (write(STDOUT_FILENO, buf, sizeof(buf)-1) != sizeof(buf)-1)
{
cout << "write error" << endl;
return 0;
} printf("before fork\n"); if ( (pid = fork()) < 0)
{
cout << "fork error" << endl;
return 0;
}
else if (pid == 0)
{
glob++;
var++;
}
else
{
sleep(2);
} printf("pid = %d, glob = %d, var = %d\n", getpid(), glob, var); return 0;
}
直接输出到控制台:
a write to stdout
before fork
pid = 1867, glob = 7, var = 89
pid = 1866, glob = 6, var = 88
使用重定向“./a.out>a.txt”,a.txt内容如下:
a write to stdout
before fork
pid = 1939, glob = 7, var = 89
before fork
pid = 1938, glob = 6, var = 88
为什会有这个差别?
先来看下“STDOUT_FILENO”和“FILE *stdout”的区别:
stdin / stdout / stderr是FILE*类型,供标准C++一级提供的文件操作函数库使用,定义在头文件<stdio.h>中。
STDIN_FILENO / STDOUT_FILENO / STDERR_FILENO 是int类型,其实质是文件描述符(值分别为0,1,2),定义在头文件<unistd.h>中。
FILE * stdin / stdout / stderr 对应的文件描述符(fd)分别是 STDIN_FILENO(0) / STDOUT_FILENO(1) / STDERR_FILENO(2) 。
两者的差别主要是标准I/O是带缓冲(具体见下面说明)的,而STDIN_FILENO / STDOUT_FILENO / STDERR_FILENO是不带缓冲的。
我们只需记住:
使用stdin / stdout / stderr的函数主要有:fread、fwrite、fclose等,基本上都以f开头。
使用STDIN_FILENO / STDOUT_FILENO / STDERR_FILENO的函数有:read、write、close等。
关于两者更详细的说明:
1.“FILE *stdout 和 STDOUT_FILENO 的区别”(http://hi.baidu.com/_%C2%B7_%C8%CB_%BC%D7_/blog/item/2d84a816882fdbd4c2fd78e1.html)
2."对stdin,stdout 和STDOUT_FILENO,STDIN_FILENO的学习"(http://www.cnblogs.com/hoys/archive/2011/05/11/2043044.html)
下面看下关于"printf"/"write"和缓冲的说明:
printf是在stdio.h中声明的函数,而标准IO都是带缓冲的,所以printf是带缓冲的。而write则是不带缓冲的。
标准IO在输入或输出到终端设备时,它们是行缓冲的,否则(文件)它们是全缓冲的。而标准错误流stderr是不使用缓冲的。更为准确的描述是:当且仅当标准输入和标准输出并不涉及交互式设备使,他们才是全缓冲的。标准出错流不使用缓冲。
下列情况会引发缓冲区的刷新(清空缓冲区):
1、缓冲区满时;
2、执行flush语句;
3、执行endl语句(printf是"\n");
4、关闭文件
综上所述,write的内容在父进程直接输出到了设备,“before fork”在主线程输出到终端后因为换行符而清空了缓冲区,所以也只输出了一次。
而重定向到"a.txt"时,printf使用的是全缓冲,所以“before fork”并未输出到设备,而是随着fork()而被复制了一份到子进程的空间中,所以输出了两次。
注意:在重定向父进程输出时,子进程也被重定向了。

Linux学习之“fork函数”的更多相关文章

  1. Linux学习之“vfork函数”

    为什么使用vfork()? 希望父子进程执行不同的代码.例如: 网络服务程序中,父进程等待客户端的服务请求,当请求达到时,父进程调用fork,使子进程处理该次请求,而父进程继续等待下一个服务请求到达. ...

  2. Linux编程之fork函数

    在Linux中,fork函数的功能就是在一个进程中创建一个新的进程,当前调用fork函数的进程就是产生的新进程的父进程,新进程在以下也称为子进程.在新进程生成之后就会在系统中开始执行. 函数原型:pi ...

  3. Linux 环境下 fork 函数和 exec 函数族的使用

    前言 接触 Linux 已经有几个月了,以前在网上看各路大神均表示 Windows 是最烂的开发平台,我总是不以为然,但是经过这段时间琢磨,确实觉得 Linux 开发给我带来不少的便利.下面总结一下学 ...

  4. Linux C 中 fork() 函数详解

    一.fork入门知识 一个进程,包括代码.数据和分配给进程的资源.fork() 函数通过系统调用创建一个与原来进程几乎完全相同的进程,也就是两个进程可以做完全相同的事,但如果初始参数或者传入的变量不同 ...

  5. 深入解析Linux中的fork函数

    1.定义 #include <unistd.h> #include<sys/types.h> pid_t fork( void ); pid_t 是一个宏定义,其实质是int, ...

  6. Unix/Linux中的fork函数

    fork函数介绍 一个现有进程可以调用fork函数创建一个新进程.该函数定义如下: #include <unistd.h> pid_t fork(void); // 返回:若成功则在子进程 ...

  7. [fork]Linux中的fork函数详解

    ---------------------------------------------------------------------------------------------------- ...

  8. 【Linux 进程】fork函数详解

    一.fork入门知识 一个进程,包括代码.数据和分配给进程的资源.fork()函数通过系统调用创建一个与原来进程几乎完全相同的进程,也就是两个进程可以做完全相同的事,但如果初始参数或者传入的变量不同, ...

  9. Linux进程之Fork函数

    Fork()函数 1.所需头文件: #include <unistd.h> #include<sys/types.h> 2.函数定义 pid_t fork( void ); p ...

随机推荐

  1. [Angular] Subscribing to the valueChanges Observable

    For example we have built a form: form = this.fb.group({ store: this.fb.group({ branch: '', code: '' ...

  2. 【oracle11g ,19】索引管理

    一.索引的分类: 1.逻辑上分为:  单列索引和复合索引  唯一索引和非唯一索引  函数索引 domain索引 2.物理上分:  分区索引和非分区索引 b-tree  bitmap 注意:表和索引最好 ...

  3. Android组件——使用DrawerLayout仿网易新闻v4.4侧滑菜单

    摘要: 转载请注明出处:http://blog.csdn.net/allen315410/article/details/42914501 概述        今天这篇博客将记录一些关于DrawerL ...

  4. 排序算法 基于Javascript

    写在前面 个人感觉:javascript对类似排序查找这样的功能已经有了很好的封装,以致于当我们想对数组排序的时候只需要调用arr.sort()方法,而查找数组元素也只需要调用indexOf()方法或 ...

  5. iOS开发系列之三 - UITextField 使用方法小结

    // 初始化输入框并设置位置和大小 UITextField *textField = [[UITextField alloc] initWithFrame:CGRectMake(10, 100, 30 ...

  6. C++开发人脸性别识别教程(5)——通过FaceRecognizer类实现性别识别

    在之前的博客中已经攻克了人脸检測的问题,我们计划在这篇博客中介绍人脸识别.性别识别方面的相关实现方法. 事实上性别识别和人脸识别本质上是相似的,由于这里仅仅是一个简单的MFC开发,主要工作并不在算法研 ...

  7. 【u225】最优分解方案

    Time Limit: 1 second Memory Limit: 128 MB [问题描述] 经过第一轮的游戏,不少同学将会获得圣诞特别礼物,但这时细心的数学课代表发现了一个问题: 留下来的人太多 ...

  8. HDU 4870 Rating 高斯消元法

    链接:http://acm.hdu.edu.cn/showproblem.php?pid=4870 题意:用两个账号去參加一种比赛,初始状态下两个账号都是零分,每次比赛都用分数低的账号去比赛.有P的概 ...

  9. 《Erlang程序设计》学习笔记-第2章 并发编程

    http://blog.csdn.net/karl_max/article/details/3977860 1. 并发原语: (1) Pid = spawn(Fun) %% 创建一个新的并发进程,用于 ...

  10. 初始化NSDictionary:(工作经验)两种方法有时候效果不一样

    方法1: NSMutableDictionary *dic = [[NSMutableDictionary alloc] init]; [dic setObject:[Hp_KeysArray obj ...