分类:
2008-12-16 10:23:32
12.9 threads and fork
一个进程可能建立多个threads,那么当其中一个thread调用fork的时候,有什么效果:
1. 只有调用fork的thread会出现在child
process里面。
2.由于多个thread可能会持有锁,那么当你fork后,可能子进程里面持有该锁的thread并不在子进程里面,那么子进程里的锁状态就处于一种无法控制的状态。
怎么办:我们需要在fork返回之前,将子进程里面的锁的状态设置为一种可以控制的状态,简单的说就是获得锁然后释放锁,这样子进程就可以处理所有的锁了。但是为了不产生race condition,这个操作应该在fork调用开始后,且返回之前就完成。因此使用pthread_atfork函数可以注册一些函数,使我们在调用fork的时候就可以触发相应的handler被调用。
#include int pthread_atfork(void (*prepare)(void), void (*parent)(void),
void (*child)(void)); |
Returns: 0 if OK, error number on failure |
一般食用方法:
1.Prepare用来在fork建立子进程的copy之前,在父进程的context里面获得锁,例如通过调用pthread_mutex_lock来获得锁
2.Parent用来在prepare将锁获得了之后,且fork建立了子进程的copy之后,在父进程的context下释放锁,即调用pthread_mutex_unlock
3. child用来在prepare将所获得之后,且fork建立了子进程的copy之后,在子进程的context下释放锁,即调用pthread_mutex_unlock。
4.然后,fork返回。此时,父进程和子进程的锁的状态都是被释放了的状态。
例子代码:
#include "apue.h"
#include
pthread_mutex_t lock1 = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t lock2 = PTHREAD_MUTEX_INITIALIZER;
void
prepare(void)
{
printf("preparing locks...\n");
pthread_mutex_lock(&lock1);
pthread_mutex_lock(&lock2);
}
void
parent(void)
{
printf("parent unlocking locks...\n");
pthread_mutex_unlock(&lock1);
pthread_mutex_unlock(&lock2);
}
void
child(void)
{
printf("child unlocking locks...\n");
pthread_mutex_unlock(&lock1);
pthread_mutex_unlock(&lock2);
}
void *
thr_fn(void *arg)
{
printf("thread started...\n");
pause();
return(0);
}
int
main(void)
{
int err;
pid_t pid;
pthread_t tid;
#if defined(BSD) || defined(MACOS)
printf("pthread_atfork is unsupported\n");
#else
if ((err = pthread_atfork(prepare, parent, child)) != 0)
err_exit(err, "can't install fork handlers");
err = pthread_create(&tid, NULL, thr_fn, 0);
if (err != 0)
err_exit(err, "can't create thread");
sleep(2);
printf("parent about to fork...\n");
if ((pid = fork()) < 0)
err_quit("fork failed");
else if (pid == 0) /* child */
printf("child returned from fork\n");
else /* parent */
printf("parent returned from fork\n");
#endif
exit(0);
}
运行结果:
$ ./a.out
thread started...
parent about to fork...
preparing locks...
child unlocking locks...
child returned from fork
parent unlocking locks...
parent returned from fork
12.10 threads and i/o
Pread和pwrite可以将定位操作,和读取/写入操作融合成一个原子操作,因此可以在没有thread的synchronize保护的情况下直接在各个thread里面调用。