Linux系统编程篇进程二的创建(fork),过程发生了什么
fork
//头文件
#include <sys/types.h>
#include <unistd.h>
//函数声明
pid_t fork(void);
//返回值
(成功)返回两次pid
返为回值为0,代表当前进程是子进程
返回值为非负数,代表当前进程为父进程
(失败),返回-1
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
int main ()
{
int pid;
printf("父进程pid=%d\n",getpid());
pid=fork();//fork之后会返回两个getpid,一个为父进程的,一个子进程的
//int pid1=getpid();
if(pid>0){
printf("这是父进程%d\n",getpid());
}
else if(pid==0){
printf("这是子进程%d\n",getpid());
}
while(1);
return 0;
}
//结果
父进程pid=12627
这是父进程12627
这是子进程12628
fork()之前的语句只会被执行一次,fork()后的语句将会分别被子进程和父进程执行
发生了什么
早期的Unix内核:
把父进程的所有内容拷贝给子进程Unix系统,用于实现一种傻瓜式的进程创建:当发出fork()系统调用时,内核原样复制父进程的整个地址空间并把复制的那一份分配给子进程。现在的Unix内核(包括Linux)共享数据段,只有当子进程更改了数据段,才会拷贝一份数据段。采用一种更为有效的方法称之为写时复制(或COW)。这种思想相当简单:父进程和子进程共享页面而不是复制页面。然而,只要页面被共享,它们就不能被修改。无论父进程和子进程何时试图写一个共享的页面,就产生一个错误,这时内核就把这个页复制到一个新的页面中并标记为可写。原来的页面仍然是写保护的:当其它进程试图写入时,内核检查写进程是否是这个页面的唯一属主;如果是,它把这个页面标记为对这个进程是可写的。
int main()
{
int a= 10;
int pid=fork();
if(pid!=0){
printf("这是父进程!\n");
}else{
printf("这是子进程!\n");
a=a+10;
}
printf("a=%d\n",a);
}
//结果
这是父进程!
a=10
这是子进程!
a=20
fork创建一个子进程的目的是啥?
1、一个父进程希望复制自己,使父、子进程同时执行不同的代码段。这在网络服务进程中是常见的——父进程等待客户端的服务请求。当这种请求到达时,父进程调用fork,使子进程处理此请求。父进程则继续等待下一个服务请求到达。
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>
int main()
{
int a= 10;
int i;
while(1){
printf("请输入\n");
scanf("%d",&i);
if(i==1){
int pid=fork();
if(pid>0){
printf("这是父进程!\n");
}else if(pid==0){
while(1){
printf("这是子进程!%d\n",getpid());
sleep(3);
}
}
}else
printf("no\n");
}
}
//结果
1这是子进程!12907
这是父进程!
请输入
这是子进程!12909
1
这是父进程!
请输入
这是子进程!12910
1
这是父进程!
请输入
这是子进程!12911
这是子进程!12908
这是子进程!12906
这是子进程!12907
这是子进程!12909
这是子进程!12910
这是子进程!12911
这是子进程!12908
这是子进程!12906
这是子进程!12907
一个进程要执行一个不同的程序,这对shell是常见的情况。在这种情况下,子进程从fork返回后立即调用exec