Outline
- 1.进程ID
- 2.创建进程 - fork
- 3.创建进程 - vfork
=================================================================================================
1. 进程ID
pid_t - 非负整型数
每个进程都有一个非负整型数表示的唯一进程ID,其中有一些为系统保留ID,如0-系统调度进程,1-init进程
- #include <unistd.h>
-
pid_t getpid(void); //获取调用进程的pid
-
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的返回值记录下来,别无它法。”
例子:
- #include <unistd.h>
-
#include <stdio.h>
-
int main()
-
{
-
pid_t pid;
-
int foo1 = 1, foo2 = 2;
-
printf("before fork()\n");
-
if ((pid = fork()) < 0 ) { /* return < 0, an error occurs */
-
printf("fork failed.\n");
-
}else if (pid == 0) { /* return 0, then we are in child process */
-
foo1++;
-
foo2++;
-
printf("child process: pid is %d, my parent pid is %d\n", getpid(), getppid());
-
}else if (pid > 0){ /* return > 0, then we are in parent process */
-
printf("parent process: pid is %d\n", getpid());
-
sleep(1); /* because we don't know child or parent is executed first*/
-
}
-
-
printf("%s: foo1 is %d, foo2 is %d\n",pid == 0 ? "child process" : "parent process", foo1, foo2);
-
return 0;
-
}
然后调用
输出结果为:
- before fork()
-
child process: pid is 7768, my parent pid is 7767
-
child process: foo1 is 2, foo2 is 3 //由此可见,child拥有自己的data段、堆、栈等,不影响父进程
-
parent process: pid is 7767
-
parent process: foo1 is 1, foo2 is 2
这次,尝试调用
输出结果变为:
- before fork()
-
child process: pid is 7788, my parent pid is 7787
-
child process: foo1 is 2, foo2 is 3
-
before fork()
-
parent process: pid is 7787
-
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)保证在父进程之前执行
- #include <unistd.h>
-
#include <stdio.h>
-
int main()
-
{
-
pid_t pid;
-
int foo1 = 1, foo2 = 2;
-
printf("before fork()\n");
-
-
//fflush(stdout);
-
if ((pid = vfork()) < 0 ) {
-
printf("fork failed.\n");
-
}else if (pid == 0) {
-
foo1++;
-
foo2++;
-
printf("child process: pid is %d, my parent pid is %d\n", getpid(), getppid());
-
_exit(0);
-
}else if (pid > 0){
-
printf("parent process: pid is %d\n", getpid());
-
}
-
-
printf("%s: foo1 is %d, foo2 is %d\n",pid == 0 ? "child process" : "parent process", foo1, foo2);
-
return 0;
-
}
执行a.out
- before fork()
- child process: pid is 10745, my parent pid is 10744
- parent process: pid is 10744
- parent process: foo1 is 2, foo2 is 3 //说明 child 影响parent中的变量
思考:
a)如果在vfork中调用的不是_exit()而是exit()结果会如何??
b)如果在vfork中部调用_exit()或者exit()会如何??
阅读(1305) | 评论(0) | 转发(0) |