1 fork函数
功能:创建一个子进程。
头文件: unistd.h
原型 pid_t fork(void);
返回值:失败返回 -1;
成功返回:① 父进程返回子进程的ID(非负整数) ②子进程返回 0
pid_t类型表示进程ID,但为了表示-1,它是有符号整型。(0不是有效进程ID,init最小,为1)
注意返回值,不是fork函数能返回两个值,而是fork后,一个进程变成两个进程,两个进程各自对fork操作,父子进程需【各自】返回一个。
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
int main()
{
pid_t pid;
printf("@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@\n");//这里只有父进程执行
pid = fork();
if(pid == -1)
{
perror("fork");
exit(1);
}
else if(pid == 0)
{
printf("this is sub process,pid=%lu,ppid=%lu\n",getpid(),getppid());
}
else
printf("this is parent,pid = %lu,ppid=%lu\n",getpid(),getppid());
printf("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n");//这里父子进程都要执行
return 0;
}
执行结果:
[root@FOSDEV test2]# ./fork_test
@@@@@@@@@@@@@@@@@@@@@@@@@@
this is parent,pid = 20453,ppid=19932
%%%%%%%%%%%%%%%
this is sub process,pid=20454,ppid=20453
%%%%%%%%%%%%%%%
2 循环创建n个子进程
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
int main()
{
pid_t pid;
printf("@@@@@@@@@@@@@@@@@@@@@@@@@@\n");
int i = 0;
for(i=0;i<5;i++)
{
pid = fork ();
if(pid == -1)
{
perror("fork");
exit(1);
}
else if(pid == 0)
{
printf("this is %d child ,pid=%lu,ppid=%lu\n",i+1,getpid(),getppid());
}
else
printf("this is parent,pid = %lu,ppid=%lu\n",getpid(),getppid());
}
printf("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n");
return 0;
}
当n为3时候,循环创建了(2^n)-1个子进程,而不是N的子进程。需要在循环的过程,保证子进程不再执行fork ,因此当(fork() == 0)时,子进程应该立即break;才正确。
3 进程共享
父子进程之间在fork后。有哪些相同,那些相异之处呢?
刚fork之后:
父子相同处: 全局变量、.data、.text、栈、堆、环境变量、用户ID、宿主目录、进程工作目录、信号处理方式…
父子不同处: 1.进程ID 2.fork返回值 3.父进程ID 4.进程运行时间 5.闹钟(定时器) 6.未决信号集
似乎,子进程复制了父进程0-3G用户空间内容,以及父进程的PCB,但pid不同。真的每fork一个子进程都要将父进程的0-3G地址空间完全拷贝一份,然后在映射至物理内存吗?
当然不是!父子进程间遵循读时共享写时复制的原则。这样设计,无论子进程执行父进程的逻辑还是执行自己的逻辑都能节省内存开销。
练习:编写程序测试,父子进程是否共享全局变。 【fork_shared.c】
重点注意!躲避父子进程共享全局变量的知识误区!
【重点】:父子进程共享:1. 文件描述符(打开文件的结构体) 2. mmap建立的映射区 (进程间通信详解)
特别的,fork之后父进程先执行还是子进程先执行不确定。取决于内核所使用的调度算法。
#include<stdio.h>
#include<unistd.h>
int var = 30;
int main()
{
pid_t pid;
pid = fork();
if(pid==0)
{
sleep(2);
printf("var = %d\n",var);
}
else
{
var = 10;
printf("var = %d\n",var);
}
sleep(3);
return 0;
}
[root@FOSDEV test2]# ./fork_share
var = 10
var = 30