进程创建之fork函数
头文件:#include<unistd.h>
#include <sys/types.h>
函数原型:pid_t fork(void); pid_t实际就是int,在sys/types.h中被宏定义的
返回值:1.创建进程失败---返回-1(失败原因有两个:1)当前的进程数已经达到了系统规定的上限,这时errno的值被设置为EAGAIN。2)系统内存不足,这时errno的值被设置为ENOMEM)
2.创建成功:子进程返回0,父进程返回子进程ID
函数说明:一个现有的进程调用fork函数创建一个新的进程,新进程称之为子进程,调用fork函数的进程称为父进程。子进程是父进程的副本,它将获得父进程数据空间、堆栈等资源的副本。子进程持有的是上述存储空间的“副本”,父子进程间不共享这些存储空间。linux将复制父进程的地址空间内容给子进程,因此,子进程有了独立的地址空间。在Linux下,一个进程在内存里有三部分的数据---"代码段"、"堆栈段"和"数据段"。"代码段",存放程序代码的数据,假如机器中有数个进程运行相同的一个程序,那么它们就可以使用相同的代码段。"堆栈段"存放的是子程序的返回地址、子程序的参数以及程序的局部变量等。“数据段”则存放程序的全局变量,常数以及动态数据分配的数据空间(比如用malloc之类的函数取得的空间)。调用fork函数,父子进程共用代码段,但是数据段和堆栈段是独立的。也就是说数据段和堆栈段的数据是相互不影响的
示例代码:
#include <stdio.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
static int s_nTmp1 = 0;
static int s_nTmp2 = 0;
int main(void)
{
int nTmp = 0;
pid_t pid = 0;
printf("Before fork\n");
pid = fork();
printf("This is a test\n");
if(pid > 0)
{
nTmp = 1;
s_nTmp1 = 1;
s_nTmp2 = 1;
printf("这是父进程,它的pid=%d,他的子进程的pid=%d\n", getpid(), pid);
printf("父进程--nTmp = %d\n", nTmp);
printf("父进程--s_nTmp1 = %d\n", s_nTmp1);
printf("父进程--s_nTmp2 = %d\n", s_nTmp2);
while(1);
}
else
{
printf("这是子进程,它的pid=%d,它的父进程的pid=%d\n", getpid(), getppid());
printf("子进程--nTmp = %d\n", nTmp);
printf("子进程--s_nTmp1 = %d\n", s_nTmp1);
printf("子进程--s_nTmp2 = %d\n", s_nTmp2);
while(1);
}
return 0;
}
执行结果:
Before fork
This is a test
这是父进程,它的pid=2515,他的子进程的pid=2516
父进程--nTmp = 1
父进程--s_nTmp1 = 1
父进程--s_nTmp2 = 1
This is a test
这是子进程,它的pid=2516,它的父进程的pid=2515
子进程--nTmp = 0
子进程--s_nTmp1 = 0
子进程--s_nTmp2 = 0
结果分析:执行结果中可以看到,在fork之前的代码只会被执行一次(Before fork只会被打印一次),而fork之后的代码都会被执行两次(This is a test打印了两次),这是因为父进程和子进程共享代码段,各执行了一次fork之后的代码。在fork之后,父进程和子进程都有自己独立数据段和堆栈段(子进程的数据段和堆栈段都是父进程的拷贝),所以,在任意进程中(无论是父进程还是子进程)对全局变量(数据段)和局部变量(堆栈段)的操作都不会影响到另一个进程中的值。
注意点:
1)执行结果也可能是
Before fork
This is a test
这是子进程,它的pid=2516,它的父进程的pid=2515
子进程--nTmp = 0
子进程--s_nTmp1 = 0
子进程--s_nTmp2 = 0
This is a test
这是父进程,它的pid=2515,他的子进程的pid=2516
父进程--nTmp = 1
父进程--s_nTmp1 = 1
父进程--s_nTmp2 = 1
即先执行父进程还是子进程是未知的,这点千万要注意。(无论哪个先执行,fork之前的代码肯定都在之前)
2)在进程的结束时,也可以不加while(1),此时会退出一个进程,然后又继续执行另一个进程,即
Before fork
This is a test
这是父进程,它的pid=2635,他的子进程的pid=2636
父进程--nTmp = 1
父进程--s_nTmp1 = 1
父进程--s_nTmp2 = 1
hcx@Linux:~/home/progress$ This is a test
这是子进程,它的pid=2636,它的父进程的pid=1
子进程--nTmp = 0
子进程--s_nTmp1 = 0
子进程--s_nTmp2 = 0
此时父进程先退出,然后子进程继续执行
进程创建之vfork函数
头文件:同fork函数
函数原型:pid_t vfork(void); pid_t实际就是int,在sys/types.h中被宏定义的
返回值:同fork函数
函数说明:vfork函数和fork函数的作用都是创建一个新的进程,但是他们有以下几点不同
1)vfork函数---父子进程共享代码段和以及数据空间(数据段和堆栈段);fork函数---父子进程共用代码段,但是数据段和堆栈段是独立的。
2)vfork函数---保证子进程先运行,只有子进程调用exit等函数退出进程时,父进程才能运行,否则阻塞;fork函数---不保证父子进程哪个先执行
示例代码:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
static int s_nTmp1 = 0;
static int s_nTmp2 = 0;
int main(void)
{
int nTmp = 0;
pid_t pid = 0;
printf("Before fork\n");
pid = vfork();
printf("This is a test\n");
if(pid > 0)
{
printf("这是父进程,它的pid=%d,他的子进程的pid=%d\n", getpid(), pid);
printf("父进程--nTmp = %d\n", nTmp);
printf("父进程--s_nTmp1 = %d\n", s_nTmp1);
printf("父进程--s_nTmp2 = %d\n", s_nTmp2);
}
else
{
nTmp = 1;
s_nTmp1 = 1;
s_nTmp2 = 1;
printf("这是子进程,它的pid=%d,它的父进程的pid=%d\n", getpid(), getppid());
printf("子进程--nTmp = %d\n", nTmp);
printf("子进程--s_nTmp1 = %d\n", s_nTmp1);
printf("子进程--s_nTmp2 = %d\n", s_nTmp2);
sleep(10);
exit(0);
}
return 0;
}
执行结果:
Before fork
This is a test
这是子进程,它的pid=2234,它的父进程的pid=2233
子进程--nTmp = 1
子进程--s_nTmp1 = 1
子进程--s_nTmp2 = 1
This is a test
这是父进程,它的pid=2233,他的子进程的pid=2234
父进程--nTmp = 1
父进程--s_nTmp1 = 1
父进程--s_nTmp2 = 1
结果分析:
调用vfork函数肯定是先执行子进程的代码,只有子进程退出后,父进程才得以运行,因此在执行完
printf("子进程--s_nTmp2 = %d\n", s_nTmp2);后,子进程休眠10s,等待10s之后子进程退出,此时才执行父进程代码。
执行结果只有上面这一种。在子进程中改变了数据段和堆栈段的数据,都会影响父进程。
注意点:调用vfork函数创建子进程,要防止互锁导致程序无法继续往下执行。比如
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int main(void)
{
int nTmp = 0;
pid_t pid = 0;
printf("Before fork\n");
pid = vfork();
printf("This is a test\n");
if(pid > 0)
{
nTmp = 1;
}
else
{
while(1)
{
if(1 == nTmp)
{
printf("执行子进程\n");
exit(0);
}
}
}
return 0;
}
这段代码在打印完This is a test之后,将阻塞,子进程一直等待nTmp等1时才会退出,而nTmp只在父进程中被赋值为1,父进程只有在子进程结束时才能执行,导致了父子进程之间互锁。
初学者笔记,若有错误,请指出,谢谢!