According to this paragraph ,the following has problem:
/* usr_interrupt is set开发者_Go百科 by the signal handler. */
if (!usr_interrupt)
pause ();
/* Do work once the signal arrives. */
...
And should use sigsuspend
instead.
But I still don't see what the problem is with pause
and how sigsuspend
solves it,
anyone can explain in more details?
Let's examine what happens when a signal arrives after you've checked usr_interrupt
but before you call pause
:
main thread signal handler ----------- -------------- if (!usr_interrupt) // this is true // signal kicks up handler usr_interrupt = 1; // handler finishes pause(); // will wait for signal
You can see in that case that you've missed the signal. Extremely important if there is no further signal incoming since your program will never action it. That's what's known as a race condition. Now let's see what happens with sigsuspend
:
main thread signal handler ----------- -------------- // set up to delay signal. sigemptyset (&mask); sigaddset (&mask, SIGUSR1); // this will delay (block) signal. // possibly do this first if USR1 // may be blocked already (check!): // sigprocmask (SIG_UNBLOCK, &mask, &old); sigprocmask (SIG_BLOCK, &mask, &old); if (!usr_interrupt) // signal arrives, delayed. // unblock signal/wait (atomically). sigsuspend (&old); // delayed handler start. usr_interrupt = 1; // handler finishes. // sigsuspend returns, clean up. sigprocmask (SIG_UNBLOCK, &mask, NULL);
In this case, there is no race condition since the signal is delayed until the main thread is ready for it.
This is a classic race condition.
Main | Signal handler --------------------|----------------------- // at this point, | // no signal has | // arrived, so we | // enter the if | | if (!usr_interrupt) | | {signal arrives...} | usr_interrupt = 1; | {...handler finishes} pause(); | | // uh-oh, we missed | // the signal! |
Now the pause()
won't get unblocked until the next signal arrives (which may never happen depending on the program).
精彩评论