- Signals are delivered to process wide instead of thread wide, a process group (may include many threads) only have a single signal handler (sigaction), but each thread may have their own signal mask
- A thread's signal mask is inherited from it's creator.
- A thread could alter its signal mask by calling pthread_sigmask(), even though sigprocmask() is almost indentical under Linux, but we should prefer pthread_sigmask(), since it's explicitly documented in POSIX 2001 for multithreaded environment.
- Based on the above notes, when many threads are waiting a (specific) signal (by using pause(), sigwait() or sigwaitinfo()), and when the signal is raised, the signal is only delivered to one (and only one) thread; the signal will caused the signal handler (setuped by sigaction) to be called, and then the blocked (the only) thread (wait for signal) is resumed. After the signal is processed, the signal will NOT be propagated among threads.
- We could deliver thread wide signal by using pthread_kill().
- Please Don't use sleep() or usleep() in threads, use nanosleep() instead, the former might be depends on signals (SIGALARM), but the latter is safe. (usleep will be deprecated in POSIX 2008)
For more details, please see related man pages, specifically ``man 3 pthread_sigmask'', which also shows a example of pthread with signals.
here is a dumb example showing pthread & signals (mask), compile it with: ``gcc -O2 sig-test2.c -o sig-test2 -Wall -lpthread'', run the program in one terminal, and then switch to another terminal, use ``pkill -USR1 sig-test2'' to test the program.
/* sig-test2.c */
#include <sys/types.h>
#include <signal.h>
#include <pthread.h>
#include <time.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
static pthread_t thread_ids[2];
static void my_sig_handler(int sig, siginfo_t* pi, void* ucontext)
{
fprintf(stderr, "got signal: %d\n", pi->si_signo);
}
static void sig_set_handler(void)
{
struct sigaction new, old;
memset(&new, 0, sizeof(new));
new.sa_sigaction = my_sig_handler;
// new.sa_flags = SA_SIGINFO | SA_RESETHAND | SA_NODEFER;
new.sa_flags = SA_SIGINFO | SA_NODEFER;
if (sigaction(SIGUSR1, &new, &old) < 0) {
fprintf(stderr, "unable to set handler!\n");
exit(1);
}
}
static void sig_block_all(void)
{
sigset_t new;
sigfillset(&new);
pthread_sigmask(SIG_BLOCK, &new, NULL);
}
static void* thread_fn(void* param)
{
sigset_t new;
int sig;
long id = (long)param;
#if 1
sigemptyset(&new);
sigaddset(&new, SIGUSR1);
sigwait(&new, &sig);
#else
sigemptyset(&new);
sigaddset(&new, SIGUSR1);
pthread_sigmask(SIG_UNBLOCK, &new, NULL);
pause();
#endif
printf("%lu restore from pause, signal: %d.\n", id, sig);
return (void*)0;
}
int main(int argc, char* argv[])
{
pthread_t tid;
long i;
sig_block_all();
sig_set_handler();
for (i = 0; i < 2; i++) {
if (pthread_create(&thread_ids[i], NULL, thread_fn, (void*)i) < 0) {
fprintf(stderr, "pthread_create: \n");
exit(1);
}
}
sleep(1);
for (i = 0; i < 2; i++) {
pthread_join(thread_ids[i], NULL);
}
return 0;
}
|
阅读(1227) | 评论(0) | 转发(0) |