Linux学习之“fork函数”

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()而被复制了一份到子进程的空间中,所以输出了两次。

注意:在重定向父进程输出时,子进程也被重定向了。

时间: 2024-08-13 23:22:26

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

Linux学习之“vfork函数”

为什么使用vfork()? 希望父子进程执行不同的代码.例如: 网络服务程序中,父进程等待客户端的服务请求,当请求达到时,父进程调用fork,使子进程处理该次请求,而父进程继续等待下一个服务请求到达. vfork与fork的函数原型相同,用于创建新进程,而该新进程的目的是exec一个新程序(执行一个可执行的文件). 由于新程序将有自己的地址空间,因此vfork函数并不将父进程的地址空间完全复制到子进程中. 注意以下两点: 1.子进程在调用exec或exit之前,在父进程的地址空间中运行. 2.v

Linux下的 fork 函数

之前只是了解到linux中的fork函数是用来创建进程,并没有太多的去学习,这里学习记录如下. 撰写不易,转载需注明出处:http://blog.csdn.net/jscese/article/details/44401389 本文来自 [jscese]的博客! 定义: 来自百科的解释:fork函数将运行着的程序分成2个(几乎)完全一样的进程,每个进程都启动一个从代码的同一位置开始执行的线程.这两个进程中的线程继续执行,就像是两个用户同时启动了该应用程序的两个副本. 通俗的来理解,就是程序跑到f

linux学习笔记 (fork && FILE && PC)

一. 下面的代码是对fork的测试 运行结果为: 可以看出,所有进程的pid 为 10604 ~ 10611  (共 8 个   2 ^ 3) 修改循环条件,让循环执行5次, 所有进程的pid 为 : 10637 ~ 10668 (共 32 个  2 ^ 5) 可以看出,循环执行n次,进程的数目为: 2 ^ n 个 二. FILE结构体: 首先定位: cd /usr/include 搜索: gerp 'FILE' stdio.h 搜索出了一大堆,但其中有一行代码:  typedef struct

Linux进程之Fork函数

Fork()函数 1.所需头文件: #include <unistd.h> #include<sys/types.h> 2.函数定义 pid_t fork( void ); pid_t 是一个宏定义,其实质是int 被定义在#include<sys/types.h>中 返回值: 若成功调用一次则返回两个值,子进程返回0,父进程返回子进程ID: 否则,出错返回-1 3.函数说明: 一个现有进程可以调用fork函数创建一个新进程.由fork创建的新进程被称为子进程(chil

Linux中的fork()函数

 一.fork入门知识 一个进程,包括代码.数据和分配给进程的资源.fork()函数通过系统调用创建一个与原来进程几乎完全相同的进程, 也就是两个进程可以做完全相同的事,但如果初始参数或者传入的变量不同,两个进程也可以做不同的事. 一个进程调用fork()函数后,系统先给新的进程分配资源,例如存储数据和代码的空间.然后把原来的进程的所有值都 复制到新的新进程中,只有少数值与原来的进程的值不同.相当于克隆了一个自己. 我们来看一个例子: /* *  fork_test.c *  version 1

关于linux下的fork()函数

上题 1. int main( ){ int i; for(i = 0; i<5;i++){ int pid = fork(); if(pid == 0){ //do something } else { //do something } } // do somthing,sleep return 0;}5101532 2 2.Linux下多少个"-"将被打印: int main(void){ int i; for(i=0;i<4;i++){ fork(); printf(

Linux学习之“exit函数”

先看下"_exit"和"exit": exit被调用时,将冲刷所有的标准I/O流,关闭所有打开的文件描述符.在传统实现中,同时也将关闭标准I/O流.即表示标准输出FILE对象的相关存储区将被清0.而_exit不会执行这些操作. 由于父子进程共享同一地址空间,当父进程恢复运行并调用printf时,不会产生任何输出,它返回-1.这就是上一节调用_exit的原因. 然而,大多数exit的现代实现不再关闭流.因为进程即将终止,内核将关闭所有已打开的文件描述符. Linux程

linux中的fork函数的基本用法

代码: 1 #include <iostream> 2 #include <string> 3 #include <cstdio> 4 #include <unistd.h> 5 #include <sys/wait.h> 6 7 using namespace std; 8 9 int main(int argc,char* argv[]){ 10 11 pid_t pid; 12 for(int i = 0; i < 1; i++){

深入理解Linux的fork函数

一.问题引入 工作期间,某系统设计师抛出如下一个问题,下面的代码,输出几个"-"?: /****************************************************************************** Copyright by Thomas Hu, All rights reserved! Filename : fork01.c Author : Thomas Hu Date : 2012-8-5 Version : 1.0 Descript