I am trying to write a multithreaded application in C for the Raspberry Pi in raspbian environment (UNIX system).
Apart from the main thread three other threads are created and do the following:
the first looks at the output of a PIR sensor and if movement is detected it takes a picture. The thread function is task1();
the second uses sigwait and alarm() to measure the temperature every given seconds. The thread function is task2()
The third thread checks if a new picture is taken and if so it does some other stuff. The synchronization with the first thread is done with a global flag, a mutex and with pthread_cond_wait. The thread function is task3().
All the thread functions have an infinite loop. The execution of the program seems good.
The main thread call the function pause() and then pthread_cancel() to exit cleanly from each thread (lowering the pins).
At first I did not use the signal handler and the process quit without calling the exiting thread functions registered with the function pthread_cleanup_push. This because pause() returns only if the handler returns. That is why I added my signal handler which returns.
In this way the pthread_cancel are called correctly and also the exiting thread functions are called correctly (the output is printed) but the process keeps running even with pressing CTRL-C or calling kill from another terminal window.
I think I messed up with the masks so that the signal generated by pthread_cancel (if any) has no effect.
Apart from this I have read that in general it is bad practice using pthread_cancel so my question is:
what is the best way to exit cleanly from each thread (especially in my case)? Shall I use another global flag? With mutex or read-write lock? Should I set it from the main thread or handler?
Any suggestion will be appreciated.
EDIT: If instead of calling pthread_cancel I use a global flag for the infinite loops, how would you set the condition in task3()?
NOTE: the code is incomplete for the sake of brevity. I tried to emphasize the logic. If needed I will add all the code.
#include<wiringPi.h>
#include<stdlib.h>
#include<stdio.h>
#include<signal.h>
#include<stdint.h>
#include<pthread.h>
g_new_pic_flag=FALSE;
pthread_cond_t g_new_pic_cond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t g_new_pic_m = PTHREAD_MUTEX_INITIALIZER;
/* FUNCTION DECLARATION */
/*We define thread exit functions so that each pin
is lowered by the thread in which it is used avoiding
race condition between the signal handler of the main thread
and the other threads*/
void exitingThreadTask1(void* arg);
void exitingThreadTask2(void* arg);
void exitingThreadTask3(void* arg);
void* task1(void *arg); //thread function for the motion sensor
void* task2(void *arg); //thread function for the temperature reading
void* task3(void *arg); //thread function to post data on IOT platforms
/*Signal handler to return from pause*/
void sig_handler(int signo);
int main()
{
int err;
sigset_t omask, mask;
pthread_t thread_motionSensor;
pthread_t thread_tempReading;
pthread_t thread_platformPost;
printf("Created threads IDs\n");
if (wiringPiSetup()<0)
{
printf("WiringPi error\n");
return -1;
}
printf("WiringPi is ok\n");
if (signal(SIGQUIT, sig_handler)==SIG_ERR)
printf("Error on recording SIGQUITHANDLER\n");
if (signal(SIGINT, sig_handler)==SIG_ERR)
printf("Error on recording SIGINTHANDLER\n");
if (signal(SIGTERM, sig_handler)==SIG_ERR)
printf("Error on recording SIGTERMHANDLER\n");
/*Create a new mask to block all signals for the following thread*/
sigfillset(&mask);
pthread_sigmask(SIG_SETMASK, &mask, &omask);
printf("Trying to create threads\n");
if ((err = pthread_create (&thread_motionSensor, NULL, task1, NULL))!=0)
{
printf("Thread 1 not created: error %d\n", err);
err_exit((const char)err, "pthread_create error");
}
printf("Thread 1 created. Trying to create Thread 2\n");
if((err = pthread_create (&thread_tempReading, NULL, task2, NULL))!=0)
{
printf("Thread 2 not created: error %d\n", err);
err_exit((const char)err, "pthread_create error");
}
printf("Thread 2 created. Trying to create Thread 3\n");
if ((err = pthread_create (&thread_platformPost, NULL, task3, NULL))!=0)
{
printf("Thread 3 not created: error %d %d\n", err);
err_exit((const char)err, "pthread_create error");
}
printf("Thread 3 created\n");
/*The main thread must block the SIGALRM but catch SIGINT
SIGQUIT, SIGTERM, SIgkILL*/
sigemptyset(&omask);
sigaddset(&omask, SIGINT);
sigaddset(&omask, SIGQUIT);
sigaddset(&omask, SIGKILL);
sigaddset(&omask, SIGTERM);
pthread_sigmask(SIG_UNBLOCK, &omask, NULL);
printf("Main thread waiting for signal\n");
pause();
printf("Exit signal received: cancelling threads\n");
pthread_cancel(thread_motionSensor);
pthread_cancel(thread_tempReading);
pthread_cancel(thread_platformPost);
pthread_join(thread_motionSensor, NULL);
pthread_join(thread_tempReading, NULL);
pthread_join(thread_platformPost, NULL);
printf("Exiting from main thread and process\n");
exit(0);
}
void* task1(void *arg)
{
//INITIALIZING
pthread_cleanup_push(exitingThreadTask1, NULL);
while(1)
{
//do stuff1
}
pthread_cleanup_pop(0);
pthread_exit(0);
}
void* task2(void *arg)
{
static const unsigned char schedule_time = 5;
int signo, err;
/*
We set a local mask with SIGALARM for the function sigwait
All signals have already been blocked
*/
sigset_t alarm_mask;
sigemptyset(&alarm_mask);
sigaddset(&alarm_mask, SIGALRM);
alarm(schedule_time);
pthread_cleanup_push(exitingThreadTask2, NULL);
while (1)
{
err = sigwait(&alarm_mask, &signo); //signo == SIGALRM check
if (err!=0)
err_exit(err, "sigwait failed\n");
//do stuff
alarm(schedule_time);
}
pthread_cleanup_pop(0);
pthread_exit(0);
}
void* task3(void *arg)
{
pthread_cleanup_push(exitingThreadTask3, NULL);
while(1)
{
pthread_mutex_lock(&g_new_pic_m);
while(g_new_pic_flag==FALSE)
{
pthread_cond_wait(&g_new_pic_cond, &g_new_pic_m);
}
pthread_mutex_unlock(&g_new_pic_m);
//do stuff
}
pthread_cleanup_pop(0);
pthread_exit(0);
}
void exitingThreadTask1(void* arg)
{
printf("Thread of task 1 exiting\n");
digitalWrite(OUTPIN, LOW);
digitalWrite(INPIN, LOW);
printf("Pins lowered\n");
pthread_exit((void*)0);
}
void exitingThreadTask2(void* arg)
{
printf("Thread of task 2 exiting\n");
digitalWrite(DHTPIN, LOW);
printf("Pin lowered\n");
pthread_exit((void*)0);
}
void exitingThreadTask3(void* arg)
{
printf("Thread of task 3 exiting\n");
pthread_exit((void*)0);
}
void sig_handler(int signo)
{
printf("Running handler to return from pause\n");
return;
}
In general, I recommend not cancelling or killing threads. I also try to minimize signal handling in threaded applications, or at least make the signal handlers very short, nonblocking and simple. It is better to have the threads run a loop, where they e.g. check a cancel flag, or if your thread does I/O with select or epoll, have the master thread write to a pipe to signal the other end to die. With C++ and pthreads, cancelling or killing can be even more disastrous, so for C++, doing a clean shutdown with custom code is even more important.
See e.g. pthread cancel and C++
You must not call pthread_exit() in the cleanup functions, because pthread_exit() will also call the cleanup function registered for the thread.
So, in your program, the cleanup function is called recursively and the threads never exit.
About the kill from another terminal, the command kill -9 and the pid of the process should always work because SIGKILL can't be ignored nor caught.
And in the signal handler function, you have to use async-signal-safe functions, printf() isn't async-signal-safe.
Another way to wait for a signal in the main thread is to use sigwait() or sigwaitinfo() instead of pause(), like you did for SIGALARM in a thread. So it won't need to register a handler function, but it will need to block the signals to be caught in all threads.
EDIT: To answer your last comment.
Exiting the threads task2() and task3() with a flag seems to be complex, because the main thread have to send SIGALRM to task2 in order to wake it up, and also signal the condition in order to wake up task3.
I modified your code to try to use a flag, but i may have missed an eventual problem because synchronizing threads may be complex.
In the case of your program, I haven't enough knwoledge to say if it is better to use pthread_cancel() and pthread_testcancel(), or to use flags. However, pthread_cancel() seems to be able to cancel without synchronization problems, threads that are waiting for signals or for a condition.
Using a flag, for task3, there could be the following problem:
task3 check the flag that is 0
main thread set the flag to 1
main thread signal the condition
task3 begin to wait for the condition
In this case, thread task3 won't exit, because it wasn't waiting when the condition was signaled. I'am not sure, but this problem is maybe avoided by protecting the flag with the same mutex we use for the condition. Because when the flag will be set and the condition signaled, task3 will be waiting for the condition or doing work out of the critical section.
I don't know if there may be a problem for task2, for example if the signal is lost due to an internal problem, but normally, the signal will be pending.
Here is the code of my test. I placed 1 as argument for the function pthread_cleanup_pop(), to make the threads execute the cleanup functions.
#include<stdlib.h>
#include<stdio.h>
#include<signal.h>
#include<stdint.h>
#include<pthread.h>
#define FALSE 0
volatile sig_atomic_t g_new_pic_flag=FALSE;
pthread_cond_t g_new_pic_cond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t g_new_pic_m = PTHREAD_MUTEX_INITIALIZER;
volatile int g_shutdown_task_3 = 0;
volatile int g_shutdown_task_1_2 = 0;
pthread_mutex_t g_shutdown_mutex = PTHREAD_MUTEX_INITIALIZER;
/* FUNCTION DECLARATION */
/*We define thread exit functions so that each pin
is lowered by the thread in which it is used avoiding
race condition between the signal handler of the main thread
and the other threads*/
void exitingThreadTask1(void* arg);
void exitingThreadTask2(void* arg);
void exitingThreadTask3(void* arg);
void* task1(void *arg); //thread function for the motion sensor
void* task2(void *arg); //thread function for the temperature reading
void* task3(void *arg); //thread function to post data on IOT platforms
/*Signal handler to return from pause*/
void sig_handler(int signo);
void err_exit(char err, char *msg) {
printf("\nError: %s\n",msg);
exit(1);
}
int main()
{
int err;
sigset_t omask, mask;
pthread_t thread_motionSensor;
pthread_t thread_tempReading;
pthread_t thread_platformPost;
printf("Created threads IDs\n");
/*
if (wiringPiSetup()<0)
{
printf("WiringPi error\n");
return -1;
}
*/
printf("WiringPi is ok\n");
if (signal(SIGQUIT, sig_handler)==SIG_ERR)
printf("Error on recording SIGQUITHANDLER\n");
if (signal(SIGINT, sig_handler)==SIG_ERR)
printf("Error on recording SIGQUITHANDLER\n");
if (signal(SIGTERM, sig_handler)==SIG_ERR)
printf("Error on recording SIGQUITHANDLER\n");
/*Create a new mask to block all signals for the following thread*/
sigfillset(&mask);
pthread_sigmask(SIG_SETMASK, &mask, &omask);
printf("Trying to create threads\n");
if ((err = pthread_create (&thread_motionSensor, NULL, task1, NULL))!=0)
{
printf("Thread 1 not created: error %d\n", err);
err_exit((const char)err, "pthread_create error");
}
printf("Thread 1 created. Trying to create Thread 2\n");
if((err = pthread_create (&thread_tempReading, NULL, task2, NULL))!=0)
{
printf("Thread 2 not created: error %d\n", err);
err_exit((const char)err, "pthread_create error");
}
printf("Thread 2 created. Trying to create Thread 3\n");
if ((err = pthread_create (&thread_platformPost, NULL, task3, NULL))!=0)
{
printf("Thread 3 not created: error %d %d\n", err);
err_exit((const char)err, "pthread_create error");
}
printf("Thread 3 created\n");
/*The main thread must block the SIGALRM but catch SIGINT
SIGQUIT, SIGTERM, SIgkILL*/
sigemptyset(&omask);
sigaddset(&omask, SIGINT);
sigaddset(&omask, SIGQUIT);
sigaddset(&omask, SIGKILL);
sigaddset(&omask, SIGTERM);
pthread_sigmask(SIG_UNBLOCK, &omask, NULL);
printf("Main thread waiting for signal\n");
pause();
printf("Exit signal received: cancelling threads\n");
pthread_mutex_lock(&g_shutdown_mutex);
g_shutdown_task_1_2 = 1;
pthread_mutex_unlock(&g_shutdown_mutex);
pthread_mutex_lock(&g_new_pic_m);
g_shutdown_task_3 = 1;
pthread_cond_signal(&g_new_pic_cond);
pthread_mutex_unlock(&g_new_pic_m);
pthread_kill(thread_tempReading,SIGALRM);
pthread_join(thread_motionSensor, NULL);
pthread_join(thread_tempReading, NULL);
pthread_join(thread_platformPost, NULL);
printf("Exiting from main thread and process\n");
exit(0);
}
void* task1(void *arg)
{
//INITIALIZING
pthread_cleanup_push(exitingThreadTask1, NULL);
while(1)
{
pthread_mutex_lock(&g_shutdown_mutex);
if(g_shutdown_task_1_2) {
pthread_mutex_unlock(&g_shutdown_mutex);
break;
}
pthread_mutex_unlock(&g_shutdown_mutex);
//do stuff1
sleep(1);
}
pthread_cleanup_pop(1);
pthread_exit(0);
}
void* task2(void *arg)
{
static const unsigned char schedule_time = 5;
int signo, err;
/*
We set a local mask with SIGALARM for the function sigwait
All signals have already been blocked
*/
sigset_t alarm_mask;
sigemptyset(&alarm_mask);
sigaddset(&alarm_mask, SIGALRM);
alarm(schedule_time);
pthread_cleanup_push(exitingThreadTask2, NULL);
while (1)
{
pthread_mutex_lock(&g_shutdown_mutex);
if(g_shutdown_task_1_2) {
pthread_mutex_unlock(&g_shutdown_mutex);
break;
}
pthread_mutex_unlock(&g_shutdown_mutex);
err = sigwait(&alarm_mask, &signo); //signo == SIGALRM check
if (err!=0)
err_exit(err, "sigwait failed\n");
pthread_mutex_lock(&g_shutdown_mutex);
if(g_shutdown_task_1_2) {
pthread_mutex_unlock(&g_shutdown_mutex);
break;
}
pthread_mutex_unlock(&g_shutdown_mutex);
//do stuff
alarm(schedule_time);
}
pthread_cleanup_pop(1);
pthread_exit(0);
}
void* task3(void *arg)
{
pthread_cleanup_push(exitingThreadTask3, NULL);
while(1)
{
pthread_mutex_lock(&g_new_pic_m);
if(g_shutdown_task_3) {
pthread_mutex_unlock(&g_new_pic_m);
break;
}
while(g_new_pic_flag==FALSE)
{
if(g_shutdown_task_3) break;
pthread_cond_wait(&g_new_pic_cond, &g_new_pic_m);
if(g_shutdown_task_3) break;
}
if(g_shutdown_task_3) {
pthread_mutex_unlock(&g_new_pic_m);
break;
}
pthread_mutex_unlock(&g_new_pic_m);
//do stuff
}
pthread_cleanup_pop(1);
pthread_exit(0);
}
void exitingThreadTask1(void* arg)
{
printf("Thread of task 1 exiting\n");
//digitalWrite(OUTPIN, LOW);
//digitalWrite(INPIN, LOW);
printf("Pins lowered\n");
}
void exitingThreadTask2(void* arg)
{
printf("Thread of task 2 exiting\n");
//digitalWrite(DHTPIN, LOW);
printf("Pin lowered\n");
}
void exitingThreadTask3(void* arg)
{
printf("Thread of task 3 exiting\n");
}
void sig_handler(int signo)
{
return;
}
Related
This code worked fine , but how to use it to kill for array of remaining threads?
#include<stdio.h>
#include<signal.h>
#include<pthread.h>
void *print1(void *tid)
{
pthread_t *td= tid;
pthread_mutex_t lock1=PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_lock(&lock1);
printf("1");
printf("2");
printf("3");
printf("4\n");
printf("Coming out of thread1 \n");
sleep(2);
pthread_mutex_unlock(&lock1);
pthread_kill(*td,SIGKILL);//killing remaining all threads
return NULL;
}
void *print2(void *arg)
{
pthread_mutex_t *lock = arg;
pthread_mutex_lock(lock);
sleep(5);
printf("5");
sleep(5);
printf("6");
sleep(5);
printf("7");
sleep(5);
printf("8\n");
fflush(stdout);
pthread_mutex_unlock(lock);
return NULL;
}
int main()
{
int s;
pthread_t tid1, tid2;
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
printf("creating Thread 1and 2 \n");
sleep(2);
pthread_create(&tid1, NULL, print1,&tid2);
pthread_create(&tid2, NULL, print2,&lock);
printf("Running Thread 1\n");
sleep(2);
pthread_join(tid1, NULL);
pthread_join(tid2, NULL);
return 0;
}
Comments: Please delete this and add some extra information about the code. The editor is not allowing me to edit the code.
here is an edited version of the code
along with some commentary
#include<signal.h>
#include<pthread.h>
void *print1(void *tid)
{
// should be in global space, so no need to pass
pthread_t *td= tid;
// this is a whole new mutex,
//should be in global space so other threads can access it
pthread_mutex_t lock1=PTHREAD_MUTEX_INITIALIZER;
// why bother with the mutex, it does nothing useful
pthread_mutex_lock(&lock1);
printf("1");
printf("2");
printf("3");
printf("4\n");
printf("Coming out of thread1 \n");
sleep(2);
pthread_mutex_unlock(&lock1);
pthread_kill(*td,SIGKILL);//killing remaining all threads return NULL;
// this exit is not correct, it should be this call:
// void pthread_exit(void *rval_ptr);
} // end function: print1
void *print2(void *arg)
{
// this should be in global memory so all threads using same mutex
pthread_mutex_t *lock = arg;
pthread_mutex_lock(lock);
sleep(5);
printf("5");
sleep(5);
printf("6");
sleep(5);
printf("7");
sleep(5);
printf("8\n");
fflush(stdout);
pthread_mutex_unlock(lock);
// this exit is not correct, it should be this call:
// void pthread_exit(void *rval_ptr);
return NULL;
} // end function: print2
int main()
{
int s;
// this should be in global memory
// so no need to pass to threads
pthread_t tid1, tid2;
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
printf("creating Thread 1and 2 \n");
// why bother to sleep here?
sleep(2);
// in these calls, the last parm should be NULL
// and the related data should be in global memory
pthread_create(&tid1, NULL, print1,&tid2);
pthread_create(&tid2, NULL, print2,&lock);
// we are still in main, so this printf is misleading
printf("Running Thread 1\n");
// no need to sleep()
// as the pthread_join calls will wait for the related thread to exit
sleep(2);
pthread_join(tid1, NULL);
pthread_join(tid2, NULL);
return 0;
} // end function: main
However you want. There is no "one right way" to do this.
Probably the easiest way is to replace your calls to sleep with calls to a function that uses pthread_cond_timedwait and a predicate that causes the thread to call pthread_exit.
In psuedo-code, replace calls to sleep with this logic:
Compute the time to sleep until.
Lock the mutex.
Check if the predicate is set to exit, if so, call pthread_exit.
Call pthread_cond_timedwait.
Check if the predicate is set to exit, if so, call pthread_exit.
Check if the time expired, if not, go to stop 4.
And to terminate the threads, do this:
Lock the mutex.
Set the predicate to exit.
Call pthread_cond_broadcast.
Release the mutex.
Call pthread_join on the threads to wait until they've terminated.
I am writing a program to demonstrate signal handling in a secondary thread. In my program, main thread spawns 10 thread and each thread calls sigwait to wait for signal. But in my case, it is main thread which is handling signa. Code is given below:
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/syscall.h>
#include <unistd.h>
#include <string.h>
#include <pthread.h>
#include <sys/types.h>
#include <errno.h>
volatile sig_atomic_t cont = 1;
volatile sig_atomic_t wsig = 0;
volatile sig_atomic_t wtid = 0;
int GetCurrentThreadId()
{
return syscall(__NR_gettid);
}
void Segv1(int, siginfo_t *, void *)
{
//printf("SIGSEGV signal on illegal memory access handled by thread: %d\n", GetCurrentThreadId());
wtid = GetCurrentThreadId();
wsig = SIGSEGV;
_exit(SIGSEGV);
}
void Fpe1(int , siginfo_t *, void *)
{
wtid = GetCurrentThreadId();
wsig = SIGFPE;
_exit(SIGFPE);
}
void User1(int, siginfo_t *, void *)
{
wtid = GetCurrentThreadId();
wsig = SIGUSR1;
}
void* ThreadFunc (void*)
{
sigset_t sigs;
sigemptyset(&sigs);
sigaddset(&sigs, SIGUSR1);
sigaddset(&sigs, SIGSEGV);
sigaddset(&sigs, SIGFPE);
pthread_sigmask(SIG_BLOCK, &sigs, NULL);
//printf("Thread: %d starts\n", GetCurrentThreadId());
while(cont) {
//printf("Thread: %d enters into loop\n", GetCurrentThreadId());
//int s = sigwaitinfo(&sigs, NULL);
//int sig;
//int s = sigwait(&sigs, &sig);
//printf("A signal\n");
/*if(s==0) {
sigaddset(&sigs, sig);
printf("Signal %d handled from thread: %d\n", sig, GetCurrentThreadId());
if(sig==SIGFPE||sig==SIGSEGV)
return NULL;
} else {
printf("sigwaitinfo failed with %d\n", s);
break;
}*/
int s = sigsuspend(&sigs);
switch(wsig) {
case SIGSEGV:
printf("Segmenation fault in thread: %d Current thread id: %d\n", wtid, GetCurrentThreadId());
exit(1);
break;
case SIGFPE:
printf("Floating point exception in thread: %d Current thread id: %d\n", wtid, GetCurrentThreadId());
exit(1);
break;
case SIGUSR1:
printf("User 1 signal in thread: %d Current thread id: %d\n", wtid, GetCurrentThreadId());
break;
default:
printf("Unhandled signal: %d in thread: %d Current thread id: %d\n", wsig, wtid, GetCurrentThreadId());
break;
}
}
printf("Thread: %d ends\n", GetCurrentThreadId());
return NULL;
}
int main()
{
printf("My PID: %d\n", getpid());
printf("SIGSEGV: %d\nSIGFPE: %d\nSIGUSR1: %d\n", SIGSEGV, SIGFPE, SIGUSR1);
//Create a thread for signal
struct sigaction act;
memset(&act, 0, sizeof act);
act.sa_sigaction = User1;
act.sa_flags = SA_SIGINFO;
//Set Handler for SIGUSR1 signal.
if(sigaction(SIGUSR1, &act, NULL)<0) {
fprintf(stderr, "sigaction failed\n");
return 1;
}
//Set handler for SIGSEGV signal.
act.sa_sigaction = Segv1;
sigaction(SIGSEGV, &act, NULL);
//Set handler for SIGFPE (floating point exception) signal.
act.sa_sigaction = Fpe1;
sigaction(SIGFPE, &act, NULL);
sigset_t sset;
sigemptyset(&sset);
sigaddset(&sset, SIGUSR1);
sigaddset(&sset, SIGSEGV);
sigaddset(&sset, SIGFPE);
//pthread_sigmask(SIG_BLOCK, &sset, NULL);
const int numthreads = 10;
pthread_t tid[numthreads];
for(int i=0;i<numthreads;++i)
pthread_create(&tid[i], NULL, ThreadFunc, NULL);
sleep(numthreads/2);
int sleepval = 15;
int pid = fork();
if(pid) {
while(sleepval) {
sleepval = sleep(sleepval);
//It might get interrupted with signal.
switch(wsig) {
case SIGSEGV:
printf("Segmenation fault in thread: %d\n", wtid);
exit(1);
break;
case SIGFPE:
printf("Floating point exception in thread: %d\n", wtid);
exit(1);
break;
case SIGUSR1:
printf("User 1 signal in thread: %d\n", wtid);
break;
default:
printf("Unhandled signal: %d in thread: %d\n", wsig, wtid);
break;
}
}
} else {
for(int i=0;i<10;++i) {
kill(getppid(), SIGUSR1);
//If sleep is not used, signal SIGUSR1 will be handled one time in parent
//as other signals will be ignored while SIGUSR1 is being handled.
sleep(1);
}
return 0;
}
int * a = 0;
//*a = 1;
int c=0;
//c = 0;
int b = 1/c; //send SIGFPE signal.
return 0;
}
Is there any rule of picking up the thread for signal handling on Linux and Mac OS X? What should I do so that signal got handled in secondary thread?
In the above program, I am not able to handle the signal in secondary thread. What is wrong with it?
I suggest you should SIG_BLOCK needed signals in main thread (commented out now) and SIG_UNBLOCK them in other threads (SIG_BLOCK now). Or you can spawn you threads and after it SIG_BLOCK in main thread, as spawned threads got their sigmask from parent.
And sigsuspend's parameter is not the signals you want to wake up on, but vice versa.
Is there any rule of picking up the thread for signal handling on Linux and Mac OS X?
There is, see Signal Generation and Delivery:
During the time between the generation of a signal and its delivery or acceptance, the signal is said to be pending. Ordinarily, this interval cannot be detected by an application. However, a signal can be blocked from delivery to a thread. If the action associated with a blocked signal is anything other than to ignore the signal, and if that signal is generated for the thread, the signal shall remain pending until it is unblocked, it is accepted when it is selected and returned by a call to the sigwait() function, or the action associated with it is set to ignore the signal. Signals generated for the process shall be delivered to exactly one of those threads within the process which is in a call to a sigwait() function selecting that signal or has not blocked delivery of the signal. If there are no threads in a call to a sigwait() function selecting that signal, and if all threads within the process block delivery of the signal, the signal shall remain pending on the process until a thread calls a sigwait() function selecting that signal, a thread unblocks delivery of the signal, or the action associated with the signal is set to ignore the signal. If the action associated with a blocked signal is to ignore the signal and if that signal is generated for the process, it is unspecified whether the signal is discarded immediately upon generation or remains pending.
I've written a little to program to try out pthread conditional waits.
But the problem is that there is no guarantee that a signal when sent out will be caught, thereby the thread losing the wakeup. How do I get around this?
#include<stdio.h>
#include<pthread.h>
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
void *thread_func1(void* arg){
printf("thread1 started\n");
pthread_mutex_lock(&mutex);
printf("thread1: signalling\n");
pthread_cond_signal(&cond);
printf("thread1: signalled\n");
pthread_mutex_unlock(&mutex);
printf("thread1: exiting\n");
pthread_exit(0);
}
void *thread_func2(void* arg){
printf("thread2 started\n");
pthread_mutex_lock(&mutex);
printf("thread2: waiting for signal..\n");
pthread_cond_wait(&cond, &mutex);
printf("thread2: signal received\n");
pthread_mutex_unlock(&mutex);
printf("thread2: exiting\n");
pthread_exit(0);
}
int main(int argc, char** argv){
pthread_t thread1, thread2;
pthread_create(&thread1, NULL, thread_func1, NULL);
pthread_create(&thread2, NULL, thread_func2, NULL);
pthread_join(thread1, 0);
pthread_join(thread2, 0);
return 0;
}
Here is an output from a run:
thread1 started
thread1: signalling
thread2 started
thread2: waiting for signal..
thread1: signalled
thread1: exiting
// nothing happens now; where is the signal??
Here's from another one (which works):
thread2 started
thread2: waiting for signal..
thread1 started
thread1: signalling
thread1: signalled
thread1: exiting
thread2: signal received
thread2: exiting
// program successfully exits
I'm not concerned about any kind of critical section for now, so I haven't used any locks.
How do I ensure this thing works for each run?
Edit: I have edited the code as per alk's answer below. I have added the initializers and locks. The original code I posted is here.
As you have noticed, thread 1 might signal the condition variable before thread 2 calls pthread_cond_wait(). The condition variable does not "remember" that it has been signaled, so the wakeup will be lost. Therefore, you need to use some kind of variable to determine whether thread 2 needs to wait.
int signalled = 0;
void *thread_func1(void* arg){
printf("thread1 started\n");
pthread_mutex_lock(&mutex);
printf("thread1: signalling\n");
signalled = 1;
pthread_cond_signal(&cond);
printf("thread1: signalled\n");
pthread_mutex_unlock(&mutex);
printf("thread1: exiting\n");
pthread_exit(0);
}
void *thread_func2(void* arg){
printf("thread2 started\n");
pthread_mutex_lock(&mutex);
printf("thread2: waiting for signal..\n");
if(!signalled) {
pthread_cond_wait(&cond, &mutex);
}
printf("thread2: signal received\n");
pthread_mutex_unlock(&mutex);
printf("thread2: exiting\n");
pthread_exit(0);
}
However, this code is still not correct. The pthreads spec states that "spurious wakeups" may occur on condition variables. This means that pthread_cond_wait() might return even if nobody has called pthread_cond_signal() or pthread_cond_broadcast(). Therefore, you need to check the flag in a loop, rather than just once:
void *thread_func2(void* arg){
printf("thread2 started\n");
pthread_mutex_lock(&mutex);
printf("thread2: waiting for signal..\n");
while(!signalled) {
pthread_cond_wait(&cond, &mutex);
}
printf("thread2: signal received\n");
pthread_mutex_unlock(&mutex);
printf("thread2: exiting\n");
pthread_exit(0);
}
Update: An alternate method to combine the function of a condition variable and a counter is to use a semaphore.
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
sem_t sem;
void *thread_func1(void* arg){
printf("thread1 started\n");
printf("thread1: signalling\n");
sem_post(&sem);
printf("thread1: signalled\n");
printf("thread1: exiting\n");
pthread_exit(0);
}
void *thread_func2(void* arg){
printf("thread2 started\n");
printf("thread2: waiting for signal..\n");
sem_wait(&sem);
printf("thread2: signal received\n");
printf("thread2: exiting\n");
pthread_exit(0);
}
int main(int argc, char** argv){
pthread_t thread1, thread2;
sem_init(&sem);
pthread_create(&thread1, NULL, thread_func1, NULL);
pthread_create(&thread2, NULL, thread_func2, NULL);
pthread_join(thread1, 0);
pthread_join(thread2, 0);
sem_destroy(&sem);
return 0;
}
For starters, your code misses to initialise both, mutex and cond.
To do so, at least do:
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
Also the mutex passed to pthread_cond_wait() shall be locked. And it is locked when then function returns.
Update:
Your code introduces a race. That is: if the thread 1 signals before thread 2 waits for the signal, thread 2 will wait forever, which most likely happend in the first trace you show.
If I setup and signal handler for SIGABRT and meanwhile I have a thread that waits on sigwait() for SIGABRT to come (I have a blocked SIGABRT in other threads by pthread_sigmask).
So which one will be processed first ? Signal handler or sigwait() ?
[I am facing some issues that sigwait() is get blocked for ever. I am debugging it currently]
main()
{
sigset_t signal_set;
sigemptyset(&signal_set);
sigaddset(&signal_set, SIGABRT);
sigprocmask(SIG_BLOCK, &signal_set, NULL);
// Dont deliver SIGABORT while running this thread and it's kids.
pthread_sigmask(SIG_BLOCK, &signal_set, NULL);
pthread_create(&tAbortWaitThread, NULL, WaitForAbortThread, NULL);
..
Create all other threads
...
}
static void* WaitForAbortThread(void* v)
{
sigset_t signal_set;
int stat;
int sig;
sigfillset( &signal_set);
pthread_sigmask( SIG_BLOCK, &signal_set, NULL ); // Dont want any signals
sigemptyset(&signal_set);
sigaddset(&signal_set, SIGABRT); // Add only SIGABRT
// This thread while executing , will handle the SIGABORT signal via signal handler.
pthread_sigmask(SIG_UNBLOCK, &signal_set, NULL);
stat= sigwait( &signal_set, &sig ); // lets wait for signal handled in CatchAbort().
while (stat == -1)
{
stat= sigwait( &signal_set, &sig );
}
TellAllThreadsWeAreGoingDown();
sleep(10);
return null;
}
// Abort signal handler executed via sigaction().
static void CatchAbort(int i, siginfo_t* info, void* v)
{
sleep(20); // Dont return , hold on till the other threads are down.
}
Here at sigwait(), i will come to know that SIGABRT is received. I will tell other threads about it. Then will hold abort signal handler so that process is not terminated.
I wanted to know the interaction of sigwait() and the signal handler.
From sigwait() documentation :
The sigwait() function suspends execution of the calling thread until
one of the signals specified in the signal set becomes pending.
A pending signal means a blocked signal waiting to be delivered to one of the thread/process. Therefore, you need not to unblock the signal like you did with your pthread_sigmask(SIG_UNBLOCK, &signal_set, NULL) call.
This should work :
static void* WaitForAbortThread(void* v){
sigset_t signal_set;
sigemptyset(&signal_set);
sigaddset(&signal_set, SIGABRT);
sigwait( &signal_set, &sig );
TellAllThreadsWeAreGoingDown();
sleep(10);
return null;
}
I got some information from this <link>
It says :
To allow a thread to wait for asynchronously generated signals, the threads library provides the sigwait subroutine. The sigwait subroutine blocks the calling thread until one of the awaited signals is sent to the process or to the thread. There must not be a signal handler installed on the awaited signal using the sigwait subroutine.
I will remove the sigaction() handler and try only sigwait().
From the code snippet you've posted, it seems you got the use of sigwait() wrong. AFAIU, you need WaitForAbortThread like below:
sigemptyset( &signal_set); // change it from sigfillset()
for (;;) {
stat = sigwait(&signal_set, &sig);
if (sig == SIGABRT) {
printf("here's sigbart.. do whatever you want.\n");
pthread_kill(tid, signal); // thread id and signal
}
}
I don't think pthread_sigmask() is really needed. Since you only want to handle SIGABRT, first init signal_set as empty then simply add SIGABRT, then jump into the infinite loop, sigwait will wait for the particular signal that you're looking for, you check the signal if it's SIGABRT, if yes - do whatever you want. NOTE the uses of pthread_kill(), use it to sent any signal to other threads specified via tid and the signal you want to sent, make sure you know the tid of other threads you want to sent signal. Hope this will help!
I know this question is about a year old, but I often use a pattern, which solves exactly this issue using pthreads and signals. It is a little length but takes care of any issues I am aware of.
I recently used in combination with a library wrapped with SWIG and called from within Python. An annoying issue was that my IRQ thread waiting for SIGINT using sigwait never received the SIGINT signal. The same library worked perfectly when called from Matlab, which didn't capture the SIGINT signal.
The solution was to install a signal handler
#define _NTHREADS 8
#include <signal.h>
#include <pthread.h>
#include <unistd.h>
#include <sched.h>
#include <linux/unistd.h>
#include <sys/signal.h>
#include <sys/syscall.h>
#include <setjmp.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h> // strerror
#define CallErr(fun, arg) { if ((fun arg)<0) \
FailErr(#fun) }
#define CallErrExit(fun, arg, ret) { if ((fun arg)<0) \
FailErrExit(#fun,ret) }
#define FailErrExit(msg,ret) { \
(void)fprintf(stderr, "FAILED: %s(errno=%d strerror=%s)\n", \
msg, errno, strerror(errno)); \
(void)fflush(stderr); \
return ret; }
#define FailErr(msg) { \
(void)fprintf(stderr, "FAILED: %s(errno=%d strerror=%s)\n", \
msg, errno, strerror(errno)); \
(void)fflush(stderr);}
typedef struct thread_arg {
int cpu_id;
int thread_id;
} thread_arg_t;
static jmp_buf jmp_env;
static struct sigaction act;
static struct sigaction oact;
size_t exitnow = 0;
pthread_mutex_t exit_mutex;
pthread_attr_t attr;
pthread_t pids[_NTHREADS];
pid_t tids[_NTHREADS+1];
static volatile int status[_NTHREADS]; // 0: suspended, 1: interrupted, 2: success
sigset_t mask;
static pid_t gettid( void );
static void *thread_function(void *arg);
static void signalHandler(int);
int main() {
cpu_set_t cpuset;
int nproc;
int i;
thread_arg_t thread_args[_NTHREADS];
int id;
CPU_ZERO( &cpuset );
CallErr(sched_getaffinity,
(gettid(), sizeof( cpu_set_t ), &cpuset));
nproc = CPU_COUNT(&cpuset);
for (i=0 ; i < _NTHREADS ; i++) {
thread_args[i].cpu_id = i % nproc;
thread_args[i].thread_id = i;
status[i] = 0;
}
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
pthread_mutex_init(&exit_mutex, NULL);
// We pray for no locks on buffers and setbuf will work, if not we
// need to use filelock() on on FILE* access, tricky
setbuf(stdout, NULL);
setbuf(stderr, NULL);
act.sa_flags = SA_NOCLDSTOP | SA_NOCLDWAIT;
act.sa_handler = signalHandler;
sigemptyset(&act.sa_mask);
sigemptyset(&mask);
sigaddset(&mask, SIGINT);
if (setjmp(jmp_env)) {
if (gettid()==tids[0]) {
// Main Thread
printf("main thread: waiting for clients to terminate\n");
for (i = 0; i < _NTHREADS; i++) {
CallErr(pthread_join, (pids[i], NULL));
if (status[i] == 1)
printf("thread %d: terminated\n",i+1);
}
// On linux this can be done immediate after creation
CallErr(pthread_attr_destroy, (&attr));
CallErr(pthread_mutex_destroy, (&exit_mutex));
return 0;
}
else {
// Should never happen
printf("worker thread received signal");
}
return -1;
}
// Install handler
CallErr(sigaction, (SIGINT, &act, &oact));
// Block SIGINT
CallErr(pthread_sigmask, (SIG_BLOCK, &mask, NULL));
tids[0] = gettid();
srand ( time(NULL) );
for (i = 0; i < _NTHREADS; i++) {
// Inherits main threads signal handler, they are blocking
CallErr(pthread_create,
(&pids[i], &attr, thread_function,
(void *)&thread_args[i]));
}
if (pthread_sigmask(SIG_UNBLOCK, &mask, NULL)) {
fprintf(stderr, "main thread: can't block SIGINT");
}
printf("Infinite loop started - CTRL-C to exit\n");
for (i = 0; i < _NTHREADS; i++) {
CallErr(pthread_join, (pids[i], NULL));
//printf("%d\n",status[i]);
if (status[i] == 2)
printf("thread %d: finished succesfully\n",i+1);
}
// Clean up and exit
CallErr(pthread_attr_destroy, (&attr));
CallErr(pthread_mutex_destroy, (&exit_mutex));
return 0;
}
static void signalHandler(int sig) {
int i;
pthread_t id;
id = pthread_self();
for (i = 0; i < _NTHREADS; i++)
if (pids[i] == id) {
// Exits if worker thread
printf("Worker thread caught signal");
break;
}
if (sig==2) {
sigaction(SIGINT, &oact, &act);
}
pthread_mutex_lock(&exit_mutex);
if (!exitnow)
exitnow = 1;
pthread_mutex_unlock(&exit_mutex);
longjmp(jmp_env, 1);
}
void *thread_function(void *arg) {
cpu_set_t set;
thread_arg_t* threadarg;
int thread_id;
threadarg = (thread_arg_t*) arg;
thread_id = threadarg->thread_id+1;
tids[thread_id] = gettid();
CPU_ZERO( &set );
CPU_SET( threadarg->cpu_id, &set );
CallErrExit(sched_setaffinity, (gettid(), sizeof(cpu_set_t), &set ),
NULL);
int k = 8;
// While loop waiting for exit condition
while (k>0) {
sleep(rand() % 3);
pthread_mutex_lock(&exit_mutex);
if (exitnow) {
status[threadarg->thread_id] = 1;
pthread_mutex_unlock(&exit_mutex);
pthread_exit(NULL);
}
pthread_mutex_unlock(&exit_mutex);
k--;
}
status[threadarg->thread_id] = 2;
pthread_exit(NULL);
}
static pid_t gettid( void ) {
pid_t pid;
CallErr(pid = syscall, (__NR_gettid));
return pid;
}
I run serveral tests and the conbinations and results are:
For all test cases, I register a signal handler by calling sigaction in the main thread.
main thread block target signal, thread A unblock target signal by calling pthread_sigmask, thread A sleep, send target signal.
result: signal handler is executed in thread A.
main thread block target signal, thread A unblock target signal by calling pthread_sigmask, thread A calls sigwait, send target signal.
result: sigwait is executed.
main thread does not block target signal, thread A does not block target signal, thread A calls sigwait, send target signal.
result: main thread is chosen and the registered signal handler is executed in the main thread.
As you can see, conbination 1 and 2 are easy to understand and conclude.
It is:
If a signal is blocked by a thread, then the process-wide signal handler registered by sigaction just can't catch or even know it.
If a signal is not blocked, and it's sent before calling sigwait, the process-wide signal handler wins. And that's why APUE the books require us to block the target signal before calling sigwait. Here I use sleep in thread A to simulate a long "window time".
If a signal is not blocked, and it's sent when sigwait has already been waiting, sigwait wins.
But you should notice that for test case 1 and 2, main thread is designed to block the target signal.
At last for test case 3, when main thread is not blocked the target signal, and sigwait in thread A is also waiting, the signal handler is executed in the main thread.
I believe the behaviour of test case 3 is what APUE talks about:
From APUE ยง12.8:
If a signal is being caught (the process has established a signal
handler by using sigaction, for example) and a thread is waiting for
the same signal in a call to sigwait, it is left up to the
implementation to decide which way to deliver the signal. The
implementation could either allow sigwait to return or invoke the
signal handler, but not both.
Above all, if you want to accomplish one thread <-> one signal model, you should:
block all signals in the main thread with pthread_sigmask (subsequent thread created in main thread inheris the signal mask)
create threads and call sigwait(target_signal) with target signal.
test code
#define _POSIX_C_SOURCE 200809L
#include <signal.h>
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
FILE* file;
void* threadA(void* argv){
fprintf(file, "%ld\n", pthread_self());
sigset_t m;
sigemptyset(&m);
sigaddset(&m, SIGUSR1);
int signo;
int err;
// sigset_t q;
// sigemptyset(&q);
// pthread_sigmask(SIG_SETMASK, &q, NULL);
// sleep(50);
fprintf(file, "1\n");
err = sigwait(&m, &signo);
if (err != 0){
fprintf(file, "sigwait error\n");
exit(1);
}
switch (signo)
{
case SIGUSR1:
fprintf(file, "SIGUSR1 received\n");
break;
default:
fprintf(file, "?\n");
break;
}
fprintf(file, "2\n");
}
void hello(int signo){
fprintf(file, "%ld\n", pthread_self());
fprintf(file, "hello\n");
}
int main(){
file = fopen("daemon", "wb");
setbuf(file, NULL);
struct sigaction sa;
sigemptyset(&sa.sa_mask);
sa.sa_handler = hello;
sigaction(SIGUSR1, &sa, NULL);
sigset_t n;
sigemptyset(&n);
sigaddset(&n, SIGUSR1);
// pthread_sigmask(SIG_BLOCK, &n, NULL);
pthread_t pid;
int err;
err = pthread_create(&pid, NULL, threadA, NULL);
if(err != 0){
fprintf(file, "create thread error\n");
exit(1);
}
pause();
fprintf(file, "after pause\n");
fclose(file);
return 0;
}
run with ./a.out & (run in the background), and use kill -SIGUSR1 pid to test. Do not use raise. raise, sleep, pause are thread-wide.
I would like to use SIGUSR1 and SIGUSR2 as arguments to pthread_kill() to suspend the execution of the running thread(i.e thread sends signal to itself) and resuming a suspended thread by a peer thread when a condition is met.
Would be gratefull for any pointers like example code or views about it.
Thanks
Signalling is used as the following example. However, in your case though, you need Condition variables
https://computing.llnl.gov/tutorials/pthreads/#ConVarSignal has an example
pthread_cond_wait (condition,mutex)
pthread_cond_signal (condition)
pthread_cond_broadcast (condition)
Example with the correct usage of the signals with pthread_kill() is demonstrated below
/* ptsig.c
This program illustrates the use of signals in threads.
Three threads including the main thread.
main thread
a. Set up a signal mask to block all signals.
b. Set up signal handlers for SIGINT and SIGUSR1.
c. Create thread_1, detached.
d. Create thread_2, nondetached.
e. Send SIGINT & SIGUSR1 to thread_1.
f. Quit.
thread_1
a. Unblock all to embrace all signals.
b. Wait for signals.
c. Send SIGINT and SIGUSR1 to thread_2
d. Wait for thread_2 to terminate
e. Print thread_2 return status.
f. Quit
thread_2
a. Unblock SIGUSR1 -- all others blocked due to inheritance.
b. Wait for signals.
c. Quit
Note: There is hardly any error checking in this example -- not a good
idea, but to make the program a bit more easier to explain.
To compile: gcc ptsig.c -lpthread
Sam Hsu (11/19/10)
*/
#define _POSIX_C_SOURCE 199506L
#include <stdio.h>
#include <pthread.h>
#include <signal.h>
#include <unistd.h>
pthread_t tid2;
static void int_handler(int signo), usr1_handler(int signo);
void millisleep(int milliseconds)
{
usleep(milliseconds * 1000);
}
main()
{
pthread_t tid1;
pthread_attr_t attr_obj; /* a thread attribute variable */
void *thread_1(void *), *thread_2(void *);
sigset_t sigmask;
struct sigaction action;
/* set up signal mask to block all in main thread */
sigfillset(&sigmask); /* to turn on all bits */
pthread_sigmask(SIG_BLOCK, &sigmask, (sigset_t *)0);
/* set up signal handlers for SIGINT & SIGUSR1 */
action.sa_flags = 0;
action.sa_handler = int_handler;
sigaction(SIGINT, &action, (struct sigaction *)0);
action.sa_handler = usr1_handler;
sigaction(SIGUSR1, &action, (struct sigaction *)0);
pthread_attr_init(&attr_obj); /* init it to default */
pthread_attr_setdetachstate(&attr_obj, PTHREAD_CREATE_DETACHED);
pthread_create(&tid1, &attr_obj, thread_1, (void *)NULL);
printf("TID(%u) created\n", (unsigned int)tid1);
pthread_attr_setdetachstate(&attr_obj, PTHREAD_CREATE_JOINABLE);
pthread_create(&tid2, &attr_obj, thread_2, (void *)NULL);
printf("TID(%u) created\n", (unsigned int)tid2);
millisleep(1000); /* for some reason a sleep is needed here */
printf("main(%u) sending SIGINT to TID(%u)\n", (unsigned int)pthread_self(), (unsigned int)tid1);
pthread_kill(tid1, SIGINT); /* not blocked by tid1 */
printf("main(%u) sending SIGUSR1 to TID(%u)\n", (unsigned int)pthread_self(), (unsigned int)tid1);
pthread_kill(tid1, SIGUSR1); /* not blocked by tid1 */
printf("main(%u) is terminating\n", (unsigned int)pthread_self());
pthread_exit((void *)NULL); /* will not terminate process */
} /* main */
void *thread_1(void *dummy)
{
int sig, status, *status_ptr = &status;
sigset_t sigmask;
sigfillset(&sigmask); /* will unblock all signals */
pthread_sigmask(SIG_UNBLOCK, &sigmask, (sigset_t *)0);
sigwait(&sigmask, &sig);
switch(sig) {
case SIGINT:
int_handler(sig);
break;
default:
break;
}
printf("TID(%u) sending SIGINT to %u\n", (unsigned int)pthread_self(), (unsigned int)tid2);
pthread_kill(tid2, SIGINT); /* blocked by tid2 */
printf("TID(%u) sending SIGUSR1 to %u\n", (unsigned int)pthread_self(), (unsigned int)tid2);
pthread_kill(tid2, SIGUSR1); /* not blocked by tid2 */
pthread_join(tid2, (void **)status_ptr);
printf("TID(%u) exit status = %d\n", (unsigned int)tid2, status);
printf("TID(%u) is terminating\n", (unsigned int)pthread_self());
pthread_exit((void *)NULL); /* calling thread will terminate */
} /* thread_1 */
void *thread_2(void *dummy)
{
int sig;
sigset_t sigmask;
sigemptyset(&sigmask); /* to zero out all bits */
sigaddset(&sigmask, SIGUSR1); /* to unblock SIGUSR1 */
pthread_sigmask(SIG_UNBLOCK, &sigmask, (sigset_t *)0);
sigwait(&sigmask, &sig);
switch(sig) {
case SIGUSR1:
usr1_handler(sig);
break;
default:
break;
}
printf("TID(%u) is terminating\n", (unsigned int)pthread_self());
pthread_exit((void *)NULL); /* calling thread will terminate */
} /* thread_2 */
static void int_handler(int dummy)
{
printf("SIGINT received by TID(%u)\n", (unsigned int)pthread_self());
} /* int_handler */
static void usr1_handler(int dummy)
{
printf("SIGUSR1 received by TID(%u)\n", (unsigned int)pthread_self());
} /* usr1_handler */
pthread_cancel() is safer relative to pthread_kill()
An example of pthread_cancel() below
#include <pthread.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#define handle_error_en(en, msg) \
do { errno = en; perror(msg); exit(EXIT_FAILURE); } while (0)
static void *
thread_func(void *ignored_argument)
{
int s;
s = pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
if (s != 0)
handle_error_en(s, "pthread_setcancelstate");
while (1) {
printf("sleeping\n");
sleep(1); /* Should get canceled while we sleep */
}
/* sleep() is a cancellation point */
/* Should never get here */
printf("thread_func(): not canceled!\n");
return NULL;
}
int
main(void)
{
pthread_t thr;
void *res;
int s;
/* Start a thread and then send it a cancellation request */
s = pthread_create(&thr, NULL, &thread_func, NULL);
if (s != 0)
handle_error_en(s, "pthread_create");
sleep(10); /* Give thread a chance to get started */
printf("main(): sending cancellation request\n");
s = pthread_cancel(thr);
if (s != 0)
handle_error_en(s, "pthread_cancel");
/* Join with thread to see what its exit status was */
s = pthread_join(thr, &res);
if (s != 0)
handle_error_en(s, "pthread_join");
if (res == PTHREAD_CANCELED)
printf("main(): thread was canceled\n");
else
printf("main(): thread wasn't canceled (shouldn't happen!)\n");
exit(EXIT_SUCCESS);
}
While I agree with Nemo, there are some valid use cases for suspending threads via signals. The susp.c code in PWPT is certainly a good base but you can also find it used in GLIBC. You might also wish to break the thread out of a blocking-IO system call (see this question) or interrupt a semaphore wait (see this question).