initial import
from http://www.informit.com/store/programming-with-posix-threads-9780201633924
This commit is contained in:
130
atfork.c
Normal file
130
atfork.c
Normal file
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* atfork.c
|
||||
*
|
||||
* Demonstrate the use of "fork handlers" to protect data
|
||||
* invariants across a fork.
|
||||
*/
|
||||
#include <sys/types.h>
|
||||
#include <pthread.h>
|
||||
#include <sys/wait.h>
|
||||
#include "errors.h"
|
||||
|
||||
pid_t self_pid; /* pid of current process */
|
||||
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
/*
|
||||
* This routine will be called prior to executing the fork,
|
||||
* within the parent process.
|
||||
*/
|
||||
void fork_prepare (void)
|
||||
{
|
||||
int status;
|
||||
|
||||
/*
|
||||
* Lock the mutex in the parent before creating the child,
|
||||
* to ensure that no other thread can lock it (or change any
|
||||
* associated shared state) until after the fork completes.
|
||||
*/
|
||||
status = pthread_mutex_lock (&mutex);
|
||||
if (status != 0)
|
||||
err_abort (status, "Lock in prepare handler");
|
||||
}
|
||||
|
||||
/*
|
||||
* This routine will be called after executing the fork, within
|
||||
* the parent process
|
||||
*/
|
||||
void fork_parent (void)
|
||||
{
|
||||
int status;
|
||||
|
||||
/*
|
||||
* Unlock the mutex in the parent after the child has been created.
|
||||
*/
|
||||
status = pthread_mutex_unlock (&mutex);
|
||||
if (status != 0)
|
||||
err_abort (status, "Unlock in parent handler");
|
||||
}
|
||||
|
||||
/*
|
||||
* This routine will be called after executing the fork, within
|
||||
* the child process
|
||||
*/
|
||||
void fork_child (void)
|
||||
{
|
||||
int status;
|
||||
|
||||
/*
|
||||
* Update the file scope "self_pid" within the child process, and unlock
|
||||
* the mutex.
|
||||
*/
|
||||
self_pid = getpid ();
|
||||
status = pthread_mutex_unlock (&mutex);
|
||||
if (status != 0)
|
||||
err_abort (status, "Unlock in child handler");
|
||||
}
|
||||
|
||||
/*
|
||||
* Thread start routine, which will fork a new child process.
|
||||
*/
|
||||
void *thread_routine (void *arg)
|
||||
{
|
||||
pid_t child_pid;
|
||||
int status;
|
||||
|
||||
child_pid = fork ();
|
||||
if (child_pid == (pid_t)-1)
|
||||
errno_abort ("Fork");
|
||||
|
||||
/*
|
||||
* Lock the mutex -- without the atfork handlers, the mutex will remain
|
||||
* 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");
|
||||
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 ();
|
||||
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");
|
||||
sleep (5);
|
||||
status = pthread_mutex_unlock (&mutex);
|
||||
if (status != 0)
|
||||
err_abort (status, "Unlock mutex");
|
||||
status = pthread_join (fork_thread, NULL);
|
||||
if (status != 0)
|
||||
err_abort (status, "Join thread");
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user