Chinaunix首页 | 论坛 | 博客
  • 博客访问: 129144
  • 博文数量: 19
  • 博客积分: 508
  • 博客等级: 下士
  • 技术积分: 306
  • 用 户 组: 普通用户
  • 注册时间: 2009-03-11 21:04
文章分类

全部博文(19)

文章存档

2011年(16)

2009年(3)

我的朋友

分类: LINUX

2011-07-13 14:41:01

Outline 

- 1.进程ID

- 2.创建进程 - fork

- 3.创建进程 - vfork

=================================================================================================

1. 进程ID
pid_t - 非负整型数
每个进程都有一个非负整型数表示的唯一进程ID,其中有一些为系统保留ID,如0-系统调度进程,1-init进程

  1. #include <unistd.h>
  2. pid_t getpid(void); //获取调用进程的pid
  3. pid_t getppid(void); //获取调用进程父进程的pid

2. 创建进程 - fork
子进程与父进程的关系:传统的做法是,在创建子进程后,它将立刻获得父进程data段、堆、栈空间的一份拷贝;但是现在更常用的做法是使用COW写时复制技术,即在子进程创建后并不立刻拷贝所有父进程的data等,而是在子进程需要访问其中某些数据时,才进行拷贝,因为子进程可能并不一定需要访问父进程所有的数据。

fork的作用是产生一个在调用进程中产生一个子进程,fork被调用一次,但是返回两次。
返回>0:表示位于子进程中
返回0:表示目前位于父进程
返回<0:出错

“fork的返回值这样规定是有道理的。fork在子进程中返回0,子进程仍可以调用getpid函数得到自己的进程id,也可以调用getppid函数得到父进程的id。在父进程中用getpid可以得到自己的进程id,然而要想得到子进程的id,只有将fork的返回值记录下来,别无它法。”

例子:
  1. #include <unistd.h>
  2. #include <stdio.h>
  3. int main()
  4. {
  5.         pid_t pid;
  6.         int foo1 = 1, foo2 = 2;
  7.         printf("before fork()\n");

  8.         if ((pid = fork()) < 0 ) { /* return < 0, an error occurs */
  9.                 printf("fork failed.\n");
  10.         }else if (pid == 0) { /* return 0, then we are in child process */
  11.                 foo1++;
  12.                 foo2++;
  13.                 printf("child process: pid is %d, my parent pid is %d\n", getpid(), getppid());
  14.         }else if (pid > 0){ /* return > 0, then we are in parent process */
  15.                 printf("parent process: pid is %d\n", getpid());
  16.                 sleep(1); /* because we don't know child or parent is executed first*/
  17.         }

  18.         printf("%s: foo1 is %d, foo2 is %d\n",pid == 0 ? "child process" : "parent process", foo1, foo2);
  19.         return 0;
  20. }

然后调用
  1. a.out
输出结果为:
  1. before fork()
  2. child process: pid is 7768, my parent pid is 7767
  3. child process: foo1 is 2, foo2 is 3 //由此可见,child拥有自己的data段、堆、栈等,不影响父进程
  4. parent process: pid is 7767
  5. parent process: foo1 is 1, foo2 is 2
这次,尝试调用
  1. a.out > ./tmp
输出结果变为:
  1. before fork()
  2. child process: pid is 7788, my parent pid is 7787
  3. child process: foo1 is 2, foo2 is 3
  4. before fork()
  5. parent process: pid is 7787
  6. parent process: foo1 is 1, foo2 is 2
问题:为什么这里出现了两次before fork呢?原因在于linux中的printf是基于行缓冲的,将输出冲定向到file以后,第一次printf并没有输出,而仅仅是输出到了buffer里,这样在fork以后,child便继承了该buffer,在chlid退出时,所有的buffer被冲洗,对于parent也是如此,因此,便有了两个before fork。

解决方法:在fork之前,调用fflush(stdout),将buffer清空,这样fork以后,child的buffer中便没有了之前的残留。

3. 创建进程 - vfork
vfork与fork的重要区别在于:
a)共享父进程的地址空间
b)保证在父进程之前执行
  1. #include <unistd.h>
  2. #include <stdio.h>
  3. int main()
  4. {
  5.         pid_t pid;
  6.         int foo1 = 1, foo2 = 2;
  7.         printf("before fork()\n");

  8.         //fflush(stdout);
  9.         if ((pid = vfork()) < 0 ) {
  10.                 printf("fork failed.\n");
  11.         }else if (pid == 0) {
  12.                 foo1++;
  13.                 foo2++;
  14.                 printf("child process: pid is %d, my parent pid is %d\n", getpid(), getppid());
  15.                 _exit(0);
  16.         }else if (pid > 0){
  17.                 printf("parent process: pid is %d\n", getpid());
  18.         }

  19.         printf("%s: foo1 is %d, foo2 is %d\n",pid == 0 ? "child process" : "parent process", foo1, foo2);
  20.         return 0;
  21. }
执行a.out
  1. before fork()
  2. child process: pid is 10745, my parent pid is 10744
  3. parent process: pid is 10744
  4. parent process: foo1 is 2, foo2 is 3    //说明 child 影响parent中的变量
思考:
a)如果在vfork中调用的不是_exit()而是exit()结果会如何??
b)如果在vfork中部调用_exit()或者exit()会如何??

阅读(1302) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~