Professional Web Applications Themes

Pthreads and SIGCHLD - UNIX Programming

Hi, A program I have relies on the parent thread which launches a new process with fork() receiving (ie having its thread of execution asynchronously interrupted by) the SIGBCHLD signal handler when the child terminates, rather than that signal handler running in another thread's thread of execution. This is because the signal handler relies on certain variables not being changed (except by itself) while it is executing. This can be guaranteed if the signal handler executes in the thread of execution of the thread which launched it, because (as the program is written) that is the only thread which uses ...

Sponsored Links
  1. #1

    Default Pthreads and SIGCHLD

    Hi,

    A program I have relies on the parent thread which launches a new process
    with fork() receiving (ie having its thread of execution asynchronously
    interrupted by) the SIGBCHLD signal handler when the child terminates,
    rather than that signal handler running in another thread's thread of
    execution.

    This is because the signal handler relies on certain variables not being
    changed (except by itself) while it is executing. This can be guaranteed
    if the signal handler executes in the thread of execution of the thread
    which launched it, because (as the program is written) that is the only
    thread which uses those variables. Of course if another thread can "pick
    up" the signal and execute the signal handler, then that guarantee no
    longer holds, because then the parent thread and its SIGCHLD handler could
    be running concurrently. To deal with that I would have to put mutexes in
    the signal handler.

    Does POSIX/pthreads say anything about this, or is it implementation/OS
    dependent? And does it make any difference if a new thread is a launched
    by the parent process after the parent process starts a new process with
    fork() (before the child process terminates)?

    Chris.

    --
    To reply by e-mail, remove the "--nospam--" in the address
    Sponsored Links
    Chris Guest

  2. #2

    Default Re: Pthreads and SIGCHLD


    Chris Vine <freeserve.co.uk> writes:
     

    Is there any reason that the parent thread could not
    call sigwait from time to time to pick up these signals?
    That way you don't need to mess with async signal handlers.

    -SEan


    Sean Guest

  3. #3

    Default Re: Pthreads and SIGCHLD

    Chris Vine wrote:
     

    First, you can't use mutexes in a signal handler. So that's not an option.
     

    Um, both. There have been some broken implementations. However, in POSIX the
    SIGCHLD signal is "process directed", which means it will be delivered to
    any arbitrary thread that does not have SIGCHLD blocked at the time it
    arrives; and if all threads have it blocked it will be held pending against
    the PROCESS until such time as ANY thread unblocks the signal.

    When a thread is created it inherits the current signal mask of the creating
    thread. That is, if thread T1 has SIGCHLD masked, and called
    pthread_create() to create thread T2, then T2 will begin with SIGCHLD
    masked as well -- even if T1 immediately UNMASKS SIGCHLD. (The inheritance
    is static, not dynamic.)

    So one option, if you're writing the main program, would be to block SIGCHLD
    in main(), before creating any threads, so that ALL threads begin with
    SIGCHLD blocked. And then unblock SIGCHLD only in that one thread that'll
    fork() a child. This won't work if more than one thread might need to
    execute your fork() code, or if any other code might possibly unblock
    SIGCHLD for any reason.

    --
    /--------------------[ com ]--------------------\
    | Hewlett-Packard Company Tru64 UNIX & VMS Thread Architect |
    | My book: http://www.awl.com/cseng/titles/0-201-63392-2/ |
    \----[ http://homepage.mac.com/dbutenhof/Threads/Threads.html ]---/
    David Guest

  4. #4

    Default Re: Pthreads and SIGCHLD

    David Butenhof wrote:

    [snip]
     

    Hmm. This is problematic. In my case, I think the easiest course is for
    the new thread to block SIGCHLD as soon as it starts, and for the main
    thread which creates the new thread to lock a mutex just before it launches
    the thread to stop any action involving the critical variables within the
    synchronous main thread in the instant between the new thread being created
    and the new thread unlocking the mutex once it has set up its signal mask.
    The main thread is in effect locking against itself until the new thread
    releases it, on the off chance that in the instant between the new thread
    starting and it setting up its own signal mask the new thread might pick up
    the signal and execute the handler before it has set itself up not to do
    so. What the signal handler does isn't important so long as it doesn't
    fiddle with the critical variables concurrently with the main thread. If I
    cannot put mutexes in the signal handler, I can at least control what the
    main synchronous thread is doing to the critical variables.

    This should work if, as I understand it correctly, the signal mask set up by
    the new thread will not affect the signal mask of the thread which created
    it.

    Incidentally, why can't you use a mutex in a signal handler, aside from
    causing mayhem if the signal is locked for too long (and what is too long)?

    On a linked point, if the main thread which does a fork() then wait()s on
    its child, could it fail if the child also does a wait() - in other words
    could a wait on all processes (not a waitpid()) by the new thread cause the
    new thread to pick up the status of the terminating process and cause the
    main thread to wait for ever? (This isn't an issue for my program, but I
    like to store these things in the memory bank).

    I've heard people say you shouldn't mix processes with threads, and now I
    understand why, but in this case it is unavoidable because after fork()ing
    the new process does an exec().

    Chris.

    --
    To reply by e-mail, remove the "--nospam--" in the address
    Chris Guest

  5. #5

    Default Re: Pthreads and SIGCHLD

    Chris Vine wrote:
     
    >
    > Hmm. This is problematic. In my case, I think the easiest course is for
    > the new thread to block SIGCHLD as soon as it starts, and for the main
    > thread which creates the new thread to lock a mutex just before it
    > launches the thread to stop any action involving the critical variables
    > within the synchronous main thread in the instant between the new thread
    > being created and the new thread unlocking the mutex once it has set up
    > its signal mask.[/ref]

    You can do that with a semaphore, but not with a mutex. Mutexes have
    ownership, and you cannot lock a mutex in one thread and unlock it in
    another. Semaphores don't have ownership, so you can sem_wait in one thread
    and sem_post in another. (You can even sem_post in a signal handler.)
     

    Each thread's signal mask (and pending mask) are completely independent.
    Only the signal ACTIONS are shared among all threads in the process. (So
    you cannot set SIGCHLD to do one thing in one thread and something else in
    another thread.)
     

    Lots of reasons. Logically it's a really bad idea because it's too easy to
    accidentally code nasty deadlocks. A signal might arrive, for example, in a
    thread that already holds the mutex. More practically, though, making mutex
    operations "async signal safe" would mean blocking signals in many
    implementations, adding much more overhead than the cost of the mutex
    operation itself.
     

    Process parentage is by process, not thread. So yes, any thread in a given
    process that does any open-ended "wait for any child" can accept
    termination of any child created by any thread in the process. This is
    precisely why there's no "pthread_joinall" as has frequently been
    requested: it'd be a mess without a thread-based ownership hierarchy. (And
    such a hierarchy would be expensive and complicated and logically a bad
    idea in the first place.)
     

    The semantics of fork() are pretty squirrelly, and the model just doesn't
    work with intra-process concurrency. Sun's "forkall()" tried to address a
    few issues at one end of the problem spectrum, and pthread_atfork()
    addresses a few at the other end, but neither is anywhere near perfect and
    there's a broad range of problems neither touches.

    The posix_spawn() function is far better than fork(), but isn't widely
    available and maybe never will be -- and is even less likely to be widely
    used because fork()/exec*() ARE everywhere, and well known despite the
    mess. (And even worse, because posix_spawn() was designed to encapsulate
    most of the odd things people do between fork and exec* in the child, it's
    a rather complicated function.)

    --
    /--------------------[ com ]--------------------\
    | Hewlett-Packard Company Tru64 UNIX & VMS Thread Architect |
    | My book: http://www.awl.com/cseng/titles/0-201-63392-2/ |
    \----[ http://homepage.mac.com/dbutenhof/Threads/Threads.html ]---/
    David Guest

  6. #6

    Default Re: Pthreads and SIGCHLD

    David Butenhof wrote:

    [snip]

    Thanks. That was very informative and useful.

    Chris

    --
    To reply by e-mail, remove the "--nospam--" in the address
    Chris Guest

Similar Threads

  1. #39528 [NEW]: PHP configuration failed while libxml2 compiled with pthreads.
    By aleksey dot ovcharenko at gmail dot com in forum PHP Bugs
    Replies: 3
    Last Post: November 16th, 10:15 AM
  2. pthreads memory leak in AIX 4.3.3.0?
    By Sanjeev in forum AIX
    Replies: 1
    Last Post: September 24th, 10:21 AM
  3. pthreads synchronization problem
    By Chris Schadl in forum UNIX Programming
    Replies: 3
    Last Post: August 17th, 08:37 PM

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139