linux进程高级属性之安全的fork
安全性问题:当线程调用fork函数时,就为子进程创建了整个进程地址空间的副本,子进程通过继承整个地址空间的副本,也会将父进程的互斥量、读写锁、条件变量的状态继承过来。也就是说,如果父进程中互斥量是锁着的,那么在子进程中互斥量也是锁着的(尽管子进程自己还没有来得及lock),这是非常不安全的,因为子进程中拥有锁的线程也许已经消失,只会保留fork的那个线程。
解决办法:
int pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void));
它会注册三个函数: prepare是在fork调用之前会被调用的,parent在fork返回父进程之前调用,child在fork返回子进程之前调用。如果在prepare中加锁所有的互斥量,在parent和child中解锁所有的互斥量,那么在fork返回之后,互斥量的状态就是未加锁。
实例:
#include<stdio.h>
#include<pthread.h>
#include<unistd.h>
#include<sys/types.h>
#include<string.h>
pthread_mutex_t mutex;
void prepare(void)
{
pthread_mutex_lock(&mutex);
printf("this is prepare process!\n");
}
void parent(void)
{
printf("this is parent process!\n");
pthread_mutex_unlock(&mutex);
}
void child(void)
{
printf("this is child process!\n");
pthread_mutex_unlock(&mutex);
}
void * thread_f(void *arg)
{
printf("this is thread_f\n");
pid_t pid;
pthread_atfork(prepare,parent,child);
pid = fork();
if(pid == 0)
{
pthread_mutex_lock(&mutex);
printf("child process!\n");
pthread_mutex_unlock(&mutex);
}
if(pid >0)
{
pthread_mutex_lock(&mutex);
printf("parent process\n");
pthread_mutex_unlock(&mutex);
}
return (void *)0;
}
int main(int argc,char *argv[])
{
pthread_t ntid;
int err,num;
err = pthread_create(&ntid,NULL,thread_f,NULL);
if(err!=0)
{
printf("Creat new thread fail\n");
return -1;
}
pthread_mutex_init(&mutex,NULL);
pthread_mutex_lock(&mutex);
sleep(1);
pthread_mutex_unlock(&mutex);
pthread_join(ntid,NULL);
return 0;
}
运行结果:
$ gcc -pthread pthread_fork.c
$ ./a.out
this is thread_f
this is prepare process!
this is parent process!
parent process
this is child process!
child process!