I have a thread that is a very simple: it sends keep-alive packets to a server, then sleeps. I would like my main thread to signal the thread to quit, but whenever I call pthread_kill() it seems to crash my process.
I tried to call sigpending() followed by sigismember() at the beginning of my while loop, but I think it is crashing because it doesn't know of any handle to take care of the signal (I was using sigaddset() before the while loop), as follow:
void* foo(void* arg)
{
sigset_t set, isSignal;
sigemptyset(&set);
if (sigaddset(&set, SIGUSR1) == -1) { /* ... */ }
while (1) {
if (sigpending(&isSignal) != 0) { /* .. */ }
else if (sigismember(&isSignal, SIGUSR1)) {
break;
}
sendKeepAlive();
sleep(SECONDS);
}
return NULL;
}
It seems pthread_kill(pth, SIGUSR1); makes the program dies. What is the right way to send the signal please? Should I use pthread_sigmask() instead?
A signal is pending when it is delivered by the OS but a process or thread has blocked it. If you haven't blocked SIGUSR1 then it is going to be delivered and the default disposition of SIGUSR1 is to terminate the process. Your sigpending
is doing nothing in this scenario; it is effectively bypassed. Either block SIGUSR1 first with pthread_sigmask
or (optionally) handle it.
Over all this is a dubious design. With the blocked/sigpending code, depending on how long SECONDS is set to you can still wait a long time before your thread loops around to discover it is time to shutdown. If you really want to use signals for this I would suggest establishing a signal handler that sets a switch. When SIGUSR1 gets delivered the handler will be invoked, it sets the switch, sleep
will be interrupted by the signal, you check for EINTR and immediately loop around to check the switch and thenpthread_exit
.
Option 1 (compiled on linux)
#define _POSIX_C_SOURCE 2
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <time.h>
#include <signal.h>
void* foo(void* arg)
{
sigset_t set, isSignal, allSigs;
sigfillset(&allSigs);
if (sigprocmask(SIG_SETMASK, &allSigs, NULL) == -1)
{
printf("sigprocmask: %m\n");
exit(1);
}
sigemptyset(&set);
if (sigaddset(&set, SIGUSR1) == -1)
{
printf("sigaddset: %m\n");
exit(1);
}
while (1)
{
if (sigpending(&isSignal) != 0)
{
printf("sigpending: %m\n");
exit(1);
}
else
if (sigismember(&isSignal, SIGUSR1))
{
printf("signal pending for thread, exiting\n");
break;
}
printf("Doing groovy thread stuff...\n");
sleep(2);
}
return NULL;
}
int main(int argc, char *argv[])
{
pthread_t tid;
int rc;
rc = pthread_create(&tid, NULL, foo, NULL);
if (rc)
{
printf("pthread_create: %m\n");
exit(1);
}
sleep(10);
pthread_kill(tid, SIGUSR1);
pthread_join(tid, NULL);
}
Option 2 (compiled on linux)
#define _POSIX_C_SOURCE 2
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <time.h>
#include <signal.h>
volatile int stop = 0;
void handler(int sig)
{
stop = 1;
}
void* foo(void* arg)
{
signal(SIGUSR1, handler); //use sigaction, i'm too lazy here
while (! stop)
{
printf("Doing groovy thread stuff...\n");
if (sleep(4) > 0)
if (errno == EINTR)
{
printf("sleep interrupted, exiting thread...\n");
continue;
}
}
return NULL;
}
int main(int argc, char *argv[])
{
pthread_t tid;
int rc;
rc = pthread_create(&tid, NULL, foo, NULL);
if (rc)
{
printf("pthread_create: %m\n");
exit(1);
}
sleep(10);
pthread_kill(tid, SIGUSR1);
pthread_join(tid, NULL);
}
Option 3 Use some other mechanism if you can. Advised.
I'd lose the signal stuff and just use a pthread conditional variable instead, for example pthread_cond_timedwait()):
IMHO...