1.fork()
#include <unistd.h>
pid_t fork();
返回值:子进程返回0,父进程返回子进程id,fork失败返回-1.
没有一个函数使得一个进程可以获得其所有子进程的ID。
子进程只有一个父进程,可以通过函数getppid()
获得父进程ID。
写时复制是说当父进程或者子进程试图对共享的区域进行修改时才将修改区域复制一份。
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
int glob = 6;
char buf[] = "a write to stdout\n";
int main(){
int var; //variable on the stack
pid_t pid;
var = 88;
if(write(STDOUT_FILENO, buf, sizeof(buf)-1) != sizeof(buf)-1)
fprintf(stderr, "write error");
printf("before fork\n");
if((pid = fork()) < 0){
fprintf(stderr, "fork error");
}
else if(pid == 0){
glob++; //child
var++;
}
else{
sleep(2);//parent
}
printf("pid = %d, glob = %d, var = %d\n", getpid(), glob, var);
exit(0);
return 0 ;
}
执行./8_1fork
输出:
a write to stdout
before fork
pid = 8646, glob = 7, var = 89
pid = 8645, glob = 6, var = 88
子进程将glob和var改变,说明子进程中的全局区与栈是和父进程独立的,不然在父进程再次执行的时候输出的glob应该是7.
如果执行:
./8_1fork > tmp
cat tmp
则输出:
a write to stdout
before fork
pid = 8762, glob = 7, var = 89
before fork
pid = 8761, glob = 6, var = 88
这里发现before fork
输出了两次,分别是子进程和父进程输出的,这是由于行缓冲与全缓冲的区别造成的,详见标准I/O缓冲:全缓冲、行缓冲、无缓冲 .
1、全缓冲 。全缓冲指的是系统在填满标准IO缓冲区之后才进行实际的IO操作;注意,对于驻留在磁盘上的文件来说通常是由标准IO库实施全缓冲。
2、行缓冲 。在这种情况下,标准IO在输入和输出中遇到换行符时执行IO操作;注意,当流涉及终端的时候,通常使用的是行缓冲。
3、无缓冲 。无缓冲指的是标准IO库不对字符进行缓冲存储;注意,标准出错流stderr通常是无缓冲的。
其次介绍一下几个退出函数:
1、exit ()。调用exit函数之后,它首先会执行一系列的清理处理,包括调用执行各终止处理程序,关闭所有标准IO流等,然后进入内核。
2、_exit ()。与exit不同的是,它不进行清理工作而直接进入内核。此函数由POSIX.1说明,放在unistd.h里面。
3、_Exit ()。同样,它也不进行清理工作而直接进入内核。此函数跟exit一样由ISO C说明,放在stdlib.h里面。
- 上例中将标准输出重定向到文件,所以是全缓冲,父进程在
printf("before fork\n");
后,before fork\n
进入父进程的缓冲区; - 在fork后,子进程复制了父进程的缓冲区,所以子进程的缓冲区中也有
before fork\n
; - 然后子进程输出
printf("pid = %d, glob = %d, var = %d\n", getpid(), glob, var);
; - 子进程结束
exit(0);
将子进程缓冲区的内容清理,输出至文件; - 然后父进程在
sleep(2)
之后继续运行printf("pid = %d, glob = %d, var = %d\n", getpid(), glob, var);
; - 父进程结束,将父进程缓冲区中的内容输出至文件。
2.vfork()
vfork()产生的子进程在父进程的空间中运行,只有在调用exec或者exit之后才会复制。
// File Name: 8_2vfork.c
// Author: princeteng
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
int glob = 6;//global data
int main(){
int var; //variable on stack
pid_t pid;
var = 88;
printf("before vfork\n");
if((pid = vfork()) < 0){
fprintf(stderr, "vfork err");
}
else if(pid == 0){
glob++; //child
var++; //modify parent's variable
_exit(0); //child terminates
}
//parent continues
printf("pid = %d, glob = %d, var = %d\n", getpid(), glob, var);
return 0 ;
}
输出:
before vfork
pid = 9475, glob = 7, var = 89
可以看出子进程修改了父进程中的全局变量以及栈中的变量。