调用fork之后, 生成的子进程继承了父亲的之前定义的句柄、局部变量、环境变量。也就是进程空间中,所有当前的数据。之后大家分道扬镳,各自为政。以下示例,展示了一种共享输出流造成的竞态。
/*
* @FileName: race.c
* @Author: wzj
* @Brief:
* 1.1.演示一种简单的进程间竞态,
*
*
*
*
* @History:
*
*
*
* @Date: 2012年06月03日星期日09:36:15
*
*/
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
static void charatatime(char*);
int
main()
{
pid_t pid;
if ((pid = fork()) < 0){
printf("fork failed \n");
return -1;
} else if(pid == 0) {
charatatime("output from child\n");
} else {
charatatime("output from parent\n");
printf("---------------------------------\n\n");
}
return 0;
}
static void
charatatime(char* str)
{
char* ptr;
int c;
//设置输出流为无缓冲区的,这样每次调用putc都会立即输出到终端
setbuf(stdout, NULL);
for(ptr = str; (c = *ptr++); )
{
putc(c, stdout);
}
}
编译运行之后,打印到终端上的字符可能是乱序的。为什么?fork之后,子进程将文件描述符表复制了一份,但是这两份文件描述符表,指向的是同一份打开文件表,而这个表,是所有进程共享的(当然了,终端有些特殊,一个会话的所有进程共享一个终端),这种描述符的继承机制,间接导致了这种竞态的产生。而对于打开文件表的共享,则要求我们访问文件之前,一定要确保其安全性,必要的话使用文件锁进行保护。
那么,有那些进程间临界区保护的手段呢?