fork_In_Linux
时间:2010-07-21 来源:Codeplayer
fork 于多线程的关系
unix下的线程有两种实现方式,分别是pthread(POSIX thread,使用libthread实现)和kthread(kernel thread,内核模拟实现,使用fork和clone系统调用,linux kernel 2.2之前的pthread也是用这种方式实现),pthread的实现和内核的实现方式有关,比如solaris支持多对多线程,即可以用多个内核线程 管理若干个用户线程,这与linux kthread有根本的差别。lz可以看看操作系统的大学教材。
1.
fork之后,操作系统会复制一个与父进程完全相同的子 进程,虽说是父子关系,但是在操作系统看来,他们更像兄弟关系,这2个进程共享代码空间,但是数据空间是互相独立的,子进程数据空间中的内容是父进程的完 整拷贝,指令指针也完全相同,但只有一点不同,如果fork成功,子进程中 fork的返回值是0,父进程中fork的返回值是子进程的进程号,如果fork不成功,父进程会返回错误。
2.
fork 之后夫子进程除非采用了同步手段,否则不能确定谁先运行,也不能确定谁先结束。认为子进程结束后父进程才从fork返回的,这是不对的,fork不是这样 的,vfork才这样。
3.
#include <unistd.h>;
#include <sys/types.h>;
main ()
{
pid_t pid;
printf("fork!"); // printf("fork!n");
pid=fork();
if (pid < 0)
printf("error in fork!");
else if (pid == 0)
printf("i am the child process, my process id is %dn",getpid());
else
printf("i am the parent process, my process id is %dn",getpid());
}
结果是
[root@localhost c]# ./a.out
fork!i am the child process, my process id is 4286
fork!i am the parent process, my process id is 4285
但我改成 printf("fork!n");后,结果是
[root@localhost c]# ./a.out
fork!
i am the child process, my process id is 4286
i am the parent process, my process id is 4285
解释:
printf("AAAAAAAA");//print 一次; 这里会print 2次
如果你将 printf("AAAAAA") 换成 printf("AAAAAAn") 那么就是只打印一次了.
主要的区别:n,回车符号
Printf的缓冲机制:printf某些内容时,OS仅把该内容放到stdout的缓冲队列里,并不实际的写到屏幕上;但是只要看到有 n 则会立即刷新stdout,马上打印出该内容.
这里,运行了 printf("AAAAAA") 后, AAAAAA 仅仅被放到了缓冲里,再运行到fork时,缓冲里面的 AAAAAA 被子进程继承了,因此在子进程度stdout缓冲里面就也有了AAAAAA.所以最终看到的是 AAAAAA 被printf了2次。
而运行 printf("AAAAAAn")后, AAAAAA 被立即打印到了屏幕上,之后fork到子进程里的stdout缓冲里没有了AAAAAA的内容,因此结果是 AAAAAA 被printf了1次。
在多线程程序里,在”自身以外的线程存在的状态”下一使用fork的话,就可能引起各种各样的问题.比较典型的例子就是,fork出来的子进程可能会死锁.请不要,在不能把握问题的原委的情况下就在多线程程序里fork子进程.
一般的,fork做如下事情
1. 父进程的内存数据会原封不动的拷贝到子进程中
2. 子进程在单线程状态下被生成
在内存区域里,静态变量*2mutex的内存会被拷贝到子进程里.而且,父进程里即使存在多个线程,但它们也不会被继承到子进程里. fork的这两个特征就是造成死锁的原因.
一个例子死锁原因的详细解释 ---
1. 线程里的doit()先执行.
2. doit执行的时候会给互斥体变量mutex加锁.
3. mutex变量的内容会原样拷贝到fork出来的子进程中(在此之前,mutex变量的内容已经被线程改写成锁定状态).
4. 子进程再次调用doit的时候,在锁定互斥体mutex的时候会发现它已经被加锁,所以就一直等待,直到拥有该互斥体的进程释放它(实际上没有人拥有这个 mutex锁).
5. 线程的doit执行完成之前会把自己的mutex释放,但这是的mutex和子进程里的mutex已经是两份内存.所以即使释放了mutex锁也不会对子 进程里的mutex造成什么影响.
规避方法:在多线程程序里,不使用fork
就是不使用fork的方法.即用pthread_create来代替fork.