Книга: Programming with POSIX® Threads

6.6.4 sigwait and sigwaitinfo

6.6.4 sigwait and sigwaitinfo

int sigwait (const sigset_t *set, int *sig);

#ifdef _POSIX_REALTIME_SIGNALS

int sigwaitinfo (const sigset_t *set, siginfo_t *info);

int sigtimedwait (const sigset_t *set, siginfo_t *info, const struct timespec *timeout);

#endif

Always use sigwait to work with asynchronous signals within threaded code.

Pthreads adds a function to allow threaded programs to deal with "asynchronous" signals synchronously. That is, instead of allowing a signal to interrupt a thread at some arbitrary point, a thread can choose to receive a signal synchronously. It does this by calling sigwait, or one of sigwait's siblings.

The signals for which you sigwait must be masked in the sigwaiting thread,and should usually be masked in all threads.

The sigwait function takes a signal set as its argument, and returns a signal number when any signal in that set occurs. You can create a thread that waits for some signal, for example, SIGINT, and causes some application activity when it occurs. The non-obvious rule is that the signals for which you wait must be masked before calling sigwait. In fact, you should ideally mask these signals in main, at the start of the program. Because signal masks are inherited by threads you create, all threads will (by default) have the signal masked. This ensures that the signal will never be delivered to any thread except the one that calls sigwait.

Signals are delivered only once. If two threads are blocked in sigwait, only one of them will receive a signal that's sent to the process. This means you can't, for example, have two independent subsystems using sigwait that catch SIGINT. It also means that the signal will not be caught by sigwait in one thread and also delivered to some signal-catching function in another thread. That's not so bad, since you couldn't do that in the old nonthreaded model either — only one signal action can be active at a time.

While sigwait, a Pthreads function, reports errors by returning an error number, its siblings, sigwaitinfo and sigtimedwait, were added to POSIX prior to Pthreads, and use the older errno mechanism. This is confusing and awkward, and that is unfortunate. The problem is that they deal with the additional information supplied by the POSIX realtime signals option (<unistd.h> defines the symbol _POSIX_REALTIME_SIGNALS), and the POSIX realtime amendment, POSIX.1b, was completed before the Pthreads amendment.

Both sigwaitinfo and sigtimedwait return the realtime signal information, siginfo_t, for signals received. In addition, sigtimedwait allows the caller to specify that sigtimedwait should return with the error EAGAIN in the event that none of the selected signals is received within the specified interval.

The sigwait.c program creates a "sigwait thread" that handles SIGINT.

23-41 The signal_waiter thread repeatedly calls sigwait, waiting for a SIGINT signal. It counts five occurrences of SIGINT (printing a message each time), and then signals a condition variable on which main is waiting. At that time, main will exit.

61-65 The main program begins by masking SIGINT. Because all threads inherit their initial signal mask from their creator, SIGINT will be masked in all threads. This prevents SIGINT from being delivered at any time except when the signal_ waiter thread is blocked in sigwait and ready to receive the signal.

? sigwait.c

1 #include <sys/types.h>
2 #include <unistd.h>
3 #include <pthread.h>
4 #include <signal.h>
5 #include "errors.h"

6
7 pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
8 pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
9 int interrupted = 0;

10 sigset_t signal set;
12 /*
13 * Wait for the SIGINT signal. When it has occurred 5 times, set the
14 * "interrupted" flag (the main thread's wait predicate) and signal a
15 * condition variable. The main thread will exit.
16 */
17 void *signal_waiter (void *arg)
18 {
19 int sig_number;
20 int signal_count = 0;
21 int status;

22
23 while (1) {
24  sigwait (&signal_set, &sig_number);
25  if (sig_number == SIGINT) {
26  printf ("Got SIGINT (%d of 5)n", signal_count+l);
27  if (++signal_count >= 5) {
28  status = pthread_mutex_lock (&mutex);
29  if (status != 0)
30  err_abort (status, "Lock mutex");
31  interrupted = 1;
32  status = pthread_cond_signal (&cond);
33  if (status != 0)
34  err_abort (status, "Signal condition");
35  status = pthread_mutex_unlock (&mutex);
36  if (status != 0)
37  err_abort (status, "Unlock mutex");
38  break;
39  }
40 }
41 }
42 return NULL;
43 }
44
45 int main (int argc, char *argv[])
46 {
47 pthread_t signal_thread_id;
48 int status;

49
50 /*
51 * Start by masking the "interesting" signal, SIGINT in the
52 * initial thread. Because all threads inherit the signal mask
53 * from their creator, all threads in the process will have
54 * SIGINT masked unless one explicitly unmasks it. The
55 * semantics of sigwait requires that all threads (including
56 * the thread calling sigwait) have the signal masked, for
57 * reliable operation. Otherwise, a signal that arrives
58 * while the sigwaiter is not blocked in sigwait might be
59 * delivered to another thread.
60 */
61 sigemptyset (&signal_set);
62 sigaddset (&signal_set, SIGINT);
63 status = pthread_sigmask (SIG_BLOCK, &signal_set, NULL);
64 if (status != 0)
65  err_abort (status, "Set signal mask"); 66
67 /*
68 * Create the sigwait thread.
69 */
70 status = pthread_create (&signal_thread_id, NULL,
71  signal_waiter, NULL);
72 if (status != 0)
73  err_abort (status, "Create sigwaiter");
74
75 /*
76 * Wait for the sigwait thread to receive SIGINT and signal
77 * the condition variable.
78 */
79 status = pthread_mutex_lock (&mutex);
80 if (status != 0)
81  err_abort (status, "Lock mutex");
82 while (!interrupted) {
83  status = pthread_cond_wait (&cond,&mutex);
84  if (status != 0)
85  err_abort (status, "Wait for interrupt");
86 }
87 status = pthread_mutex_unlock (&mutex);
88 if (status != 0)
89  err_abort (status, "Unlock mutex");
90 printf ("Main terminating with SIGINTn");
91 return 0;
92 }

Оглавление книги


Генерация: 1.400. Запросов К БД/Cache: 3 / 1
поделиться
Вверх Вниз