* locked in the child process and this lock attempt will hang (or fail
* with EDEADLK) in the child.
*/
status = pthread_mutex_lock (&mutex);
if (status != 0)
err_abort (status, "Lock in child");
printf("After fork\n");
status = pthread_mutex_unlock (&mutex);
if (status != 0)
err_abort (status, "Unlock in child");
printf ("After fork: %d (%d)\n", child_pid, self_pid);
if (child_pid != 0) {
if ((pid_t)-1 == waitpid (child_pid, (int*)0, 0))
errno_abort ("Wait for child");
}
return NULL;
}
int main (int argc, char *argv[])
{
pthread_t fork_thread;
int atfork_flag = 1;
int status;
if (argc > 1)
atfork_flag = atoi (argv[1]);
if (atfork_flag) {
status = pthread_atfork (fork_prepare, fork_parent, fork_child);
if (status != 0)
err_abort (status, "Register fork handlers");
}
self_pid = getpid ();
printf("main self_pid = %d\n",self_pid);
status = pthread_mutex_lock (&mutex);
if (status != 0)
err_abort (status, "Lock mutex");
/*
* Create a thread while the mutex is locked. It will fork a process,
* which (without atfork handlers) will run with the mutex locked.
*/
status = pthread_create (&fork_thread, NULL, thread_routine, NULL);
if (status != 0)
err_abort (status, "Create thread");
printf("before sleep\n");
sleep (5);
printf("after sleep\n");
status = pthread_mutex_unlock (&mutex);
if (status != 0)
err_abort (status, "Unlock mutex");
printf("main unlock\n");
status = pthread_join (fork_thread, NULL);
if (status != 0)
err_abort (status, "Join thread");
printf("huangcheng \n");
return 0;
}19~32 函数fork_prepare是prepare处理器。在创建子进程前,它将在父进程内被fork调用。该函数改变的任何状态(特别是被锁住的互斥量)将被拷贝进子进程。fork_prepare函数锁住程序的互斥量。
38~49 函数fork_parent是parent处理器。在创建子进程后,它将在父进程内被fork调用。总的来说,一个parent处理器应该取消在parent处理器中做的处理,以便父进程能正常继续。fork_parent函数解锁fork_prepare锁住的互斥量。
55~68 函数fork_child是child处理器。它将在子进程被fork调用。在大多数情况下,child处理器需要执行在fork_parent处理器做过的处理,解锁状态以便子进程能继续运行。它可能也需要执行附加的清除操作,例如,fork_child锁住self_pid变量为子进程的pid,同时解锁进程互斥量。
73~100 在创建子进程以后,它将继续执行thread_routine代码,thread_routine函数解锁互斥量。当运行fork处理器时,fork调用将被阻塞(当prepare处理器锁住互斥量时)直到互斥量可用。没有fork处理器,线程将在主函数解锁互斥量前调用fork,并且线程将在这个点上在子进程挂起。
117~130 主程序在创建将调用fork的线程之前锁住互斥量。然后,它睡眠若干秒以保证当互斥量被锁住时,线程能够调用fork,然后解锁互斥量。运用pthread_routine的线程将总是在父进程中成功,因为它将简单的阻塞直到主程序释放锁。
运行结果:
main self_pid = 5564
before sleep
after sleep
main unlock
fork_prepare
fork_parent
After fork
After fork: 5568 (5564)
fork_child: self_pid = 5568
After fork
After fork: 0 (5568)
huangcheng
2.exec
exec函数没有因为引入线程受到很多影响。exec函数的功能是消除当前程序的环境并且用一个新程序代替它。对exec的调用,将很快的终止进程内除调用exec的线程外的所有线程。他们不执行清除处理器或线程私有数据destructors——线程只是简单的停止存在。
所有的同步对象也消失了,除了 pshared互斥量(使用PTHREAD_PROCESS_SHARED属性值创建的互斥量)和pshared条件变量。因为只要共享内存被一些进程映射,后者仍然是有用的。然而,你应该解锁当前进程可能锁住的任何pshared互斥量——系统不会为你解锁它们。
3.进程结束
在一个非线程程序中,对于exit函数的显示调用和从程序主函数返回有一样的效果,指进程退出。Pthreads增加了pthread_exit函数,该函数能在进程继续运行的同时导致单个线程的退出。
在一个多线程程序中,主函数是“进程主线程的启动函数”。尽管从任何其他线程的启动函数返回就像调用pthread_exit终止线程一样,但是从主函数返回将终止整个进程。与进程相关的所有内存(和线程)将消失。线程不会执行清除处理器或线程私有数据destructors函数。调用exit具有同样的效果。
当你不想使用起始