Chinaunix首页 | 论坛 | 博客
  • 博客访问: 381981
  • 博文数量: 124
  • 博客积分: 2911
  • 博客等级: 少校
  • 技术积分: 1050
  • 用 户 组: 普通用户
  • 注册时间: 2010-05-15 15:57
文章分类

全部博文(124)

文章存档

2012年(6)

2011年(26)

2010年(92)

我的朋友

分类: C/C++

2010-07-21 17:08:10

0.
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 ;
#include ;

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次。

4.
   在多线程程序里,在”自身以外的线程存在的状态”下一使用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.
阅读(784) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~