I have to code a multithreaded(say 2 threads) program where each of these threads do a different task. Also, these threads must keep running infinitely in the background once started. Here is what I have done. Can somebody please give me some feedback if the method is good and if you see some problems. Also, I would like to know how to shut the threads in a systematic way once I terminate the execution say with Ctrl+C.
The main function creates two threads and let them run infinitely as below.
Here is the skeleton:
void *func1();
void *func2();
int main(int argc, char *argv[])
{
pthread_t th1,th2;
pthread_create(&th1, NULL, func1, NULL);
pthread_create(&th2, NULL, func2, NULL);
fflush (stdout);
for(;;){
}
exit(0); //never reached
}
void *func1()
{
while(1){
//do something
}
}
void *func2()
{
while(1){
//do something
}
}
Thanks.
Edited code using inputs from the answers:
Am I exiting the threads properly?
#include <stdlib.h> /* exit() */
#include <stdio.h> /* standard in and output*/
#include <pthread.h>
#include <unistd.h>
#include <time.h>
#include <sys/time.h>
#include <sys/types.h>
#include <signal.h>
#include <semaphore.h>
sem_t end;
void *func1();
void *func2();
void ThreadTermHandler(int signo){
if (signo == SIGINT) {
printf("Ctrl+C detected !!! \n");
sem_post(&end);
}
}
void *func1()
{
int value;
for(;;){
sem_getvalue(&end, &value);
while(!value){
printf("in thread 1 \n");
}
}
return 0;
}
void *func2()
{
int value;
for(;;){
sem_getvalue(&end, &value);
while(!value){
printf("value = %d\n", value);
}
}
return 0;
}
int main(int argc, char *argv[])
{
sem_init(&end, 0, 0);
pthread_t th1,th2;
int value = -2;
pthread_create(&th1, NULL, func1, NULL);
pthread_create(&th2, NULL, func2, NULL);
struct sigaction sa;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_SIGINFO;
sa.sa_sigaction = ThreadTermHandler;
// Establish a handler to catch CTRL+c and use it for exiting.
if (sigaction(SIGINT, &sa, NULL) == -1) {
perror("sigaction for Thread Termination failed");
exit( EXIT_FAILURE );
}
/* Wait for SIGINT. */
while (sem_wait(&end)!=0){}
//{
printf("Terminating Threads.. \n");
sem_post(&end);
sem_getvalue(&end, &value);
/* SIGINT received, cancel threads. */
pthread_cancel(th1);
pthread_cancel(th2);
/* Join threads. */
pthread_join(th1, NULL);
pthread_join(th2, NULL);
//}
exit(0);
}
There are mainly two approaches for thread termination.
Use a cancellation point. The thread will terminate when requested to cancel and it reaches a cancellation point, thus ending execution in a controlled fashion;
Use a signal. Have the threads install a signal handler which provides a mechanism for termination (setting a flag and reacting to EINTR).
Both approaches has caveats. Refer to Kill Thread in Pthread Library for more details.
In your case, it seems a good opportunity to use cancellation points. I will work with a commented example. The error-checking has been omitted for clarity.
#define _POSIX_C_SOURCE 200809L
#include <pthread.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
void sigint(int signo) {
(void)signo;
}
void *thread(void *argument) {
(void)argument;
for (;;) {
// Do something useful.
printf("Thread %u running.\n", *(unsigned int*)argument);
// sleep() is a cancellation point in this example.
sleep(1);
}
return NULL;
}
int main(void) {
// Block the SIGINT signal. The threads will inherit the signal mask.
// This will avoid them catching SIGINT instead of this thread.
sigset_t sigset, oldset;
sigemptyset(&sigset);
sigaddset(&sigset, SIGINT);
pthread_sigmask(SIG_BLOCK, &sigset, &oldset);
// Spawn the two threads.
pthread_t thread1, thread2;
pthread_create(&thread1, NULL, thread, &(unsigned int){1});
pthread_create(&thread2, NULL, thread, &(unsigned int){2});
// Install the signal handler for SIGINT.
struct sigaction s;
s.sa_handler = sigint;
sigemptyset(&s.sa_mask);
s.sa_flags = 0;
sigaction(SIGINT, &s, NULL);
// Restore the old signal mask only for this thread.
pthread_sigmask(SIG_SETMASK, &oldset, NULL);
// Wait for SIGINT to arrive.
pause();
// Cancel both threads.
pthread_cancel(thread1);
pthread_cancel(thread2);
// Join both threads.
pthread_join(thread1, NULL);
pthread_join(thread2, NULL);
// Done.
puts("Terminated.");
return EXIT_SUCCESS;
}
The need for blocking/unblocking signals is that if you send SIGINT to the process, any thread may be able to catch it. You do so before spawning the threads to avoid having them doing it by themselves and needing to synchronize with the parent. After the threads are created, you restore the mask and install a handler.
Cancellation points can be tricky if the threads allocates a lot of resources; in that case, you will have to use pthread_cleanup_push() and pthread_cleanup_pop(), which are a mess. But the approach is feasible and rather elegant if used properly.
The answer depends a lot on what you want to do when the user presses CtrlC.
If your worker threads are not modifying data that needs to be saved on exit, you don't need to do anything. The default action of SIGINT is to terminate the process, and that includes all threads that make up the process.
If your threads do need to perform cleanup, however, you've got some work to do. There are two separate issues you need to consider:
How you handle the signal and get the message to threads that they need to terminate.
How your threads receive and handle the request to terminate.
First of all, signal handlers are a pain. Unless you're very careful, you have to assume most library functions are not legal to call from a signal handler. Fortunately, sem_post is specified to be async-signal-safe, and can meet your requirements perfectly:
At the beginning of your program, initialize a semaphore with sem_init(&exit_sem, 0, 0);
Install a signal handler for SIGINT (and any other termination signals you want to handle, like SIGTERM) that performs sem_post(&exit_sem); and returns.
Replace the for(;;); in the main thread with while (sem_wait(&exit_sem)!=0).
After sem_wait succeeds, the main thread should inform all other threads that they should exit, then wait for them all to exit.
The above can also be accomplished without semaphores using signal masks and sigwaitinfo, but I prefer the semaphore approach because it doesn't require you to learn lots of complicated signal semantics.
Now, there are several ways you could handle informing the worker threads that it's time to quit. Some options I see:
Having them check sem_getvalue(&exit_sem) periodically and cleanup and exit if it returns a nonzero value. Note however that this will not work if the thread is blocked indefinitely, for example in a call to read or write.
Use pthread_cancel, and carefully place cancellation handlers (pthread_cleanup_push) all over the place.
Use pthread_cancel, but also use pthread_setcancelstate to disable cancellation during most of your code, and only re-enable it when you're going to perform blocking IO operations. This way you need only put the cleanup handlers just in the places where cancellation is enabled.
Learn advanced signal semantics, and setup an additional signal and interrupting signal handler which you send to all threads via pthread_kill which will cause blocking syscalls to return with an EINTR error. Then your threads can act on this and exit the normal C way via a string of failure returns all the way back up the the start function.
I would not recommend approach 4 for beginners, because it's hard to get right, but for advanced C programmers it may be the best because it allows you to use the existing C idiom of reporting exceptional conditions via return values rather than "exceptions".
Also note that with pthread_cancel, you will need to periodically call pthread_testcancel if you are not calling any other functions which are cancellation points. Otherwise the cancellation request will never be acted upon.
This is a bad idea:
for(;;){
}
because your main thread will execute unnecessary CPU instructions.
If you need to wait in the main thread, use pthread_join as answered in this question: Multiple threads in C program
What you have done works, I see no obvious problems with it (except that you are ignoring the return value of pthread_create). Unfortunately, stopping threads is more involved than you might think. The fact that you want to use signals is another complication. Here's what you could do.
In the "children" threads, use pthread_sigmask to block signals
In the main thread, use sigsuspend to wait for a signal
Once you receive the signal, cancel (pthread_cancel) the children threads
Your main thread could look something like this:
/* Wait for SIGINT. */
sigsuspend(&mask);
/* SIGINT received, cancel threads. */
pthread_cancel(th1);
pthread_cancel(th2);
/* Join threads. */
pthread_join(th1, NULL);
pthread_join(th2, NULL);
Obviously, you should read more about pthread_cancel and cancellation points. You could also install a cleanup handler. And of course, check every return value.
Looked at your updated coded and it still does not look right.
Signal handling must be done in only one thread. Signals targeted for a process (such as SIGINT) get delivered to any thread that does not have that signal blocked. In other words, there is no guarantee that given the three threads you have it is going to be the main thread that receives SIGINT. In multi-threaded programs the best practise is too block all signals before creating any threads, and once all threads have been created unblock the signals in the main thread only (normally it is the main thread that is in the best position to handle signals). See Signal Concepts and Signalling in a Multi-Threaded Process for more.
pthread_cancel is best avoided, there no reason to ever use it. To stop the threads you should somehow communicate to them that they should terminate and wait till they have terminated voluntarily. Normally, the threads will have some sort of event loop, so it should be relatively straightforward to send the other thread an event.
Wouldn't it be much easier to just call pthread_cancel and use pthread_cleanup_push in the thread function to potentially clean up the data that was dynamically allocated by the thread or do any termination tasks that was required before the thread stops.
So the idea would be:
write the code to handle signals
when you do ctrl+c ... the handling function is called
this function cancels the thread
each thread which was created set a thread cleanup function using pthread_cleanup_push
when the tread is cancelled the pthread_cleanup_push's function is called
join all threads before exiting
It seems like a simple and natural solution.
static void cleanup_handler(void *arg)
{
printf("Called clean-up handler\n");
}
static void *threadFunc(void *data)
{
ThreadData *td = (ThreadData*)(data);
pthread_cleanup_push(cleanup_handler, (void*)something);
while (1) {
pthread_testcancel(); /* A cancellation point */
...
}
pthread_cleanup_pop(cleanup_pop_arg);
return NULL;
}
You don't need the foor loop in the main. A th1->join(); th2->join(); will suffice as a wait condition since the threads never end.
To stop the threads you could use a global shared var like bool stop = false;, then when catching the signal (Ctrl+Z is a signal in UNIX), set stop = true aborting the threads, since you are waiting with join() the main program will also exit.
example
void *func1(){
while(!stop){
//do something
}
}
Related
I'm building a generic program written in C-UNIX (using Linux so I don't care about BSD or WIN functions), that creates two threads to handle the communication with a server.
void init_threads(int socket_desc) {
pthread_t chat_threads[2];
ret = pthread_create(&chat_threads[0], NULL, receiveMessage, (void*)(long)socket_desc);
PTHREAD_ERROR_HELPER(ret, "Errore creazione thread ricezione messaggi");
ret = pthread_create(&chat_threads[1], NULL, sendMessage, (void*)(long)socket_desc);
PTHREAD_ERROR_HELPER(ret, "Errore creazione thread invio messaggi");
}
Since this program will be launched from shell I want to implement the CTRL-C possibility and so did I with this line of code:
signal(SIGINT,kill_handler);
// and its related function
void kill_handler() {
// retrive threads_id
// call pthread_exit on the two threads
printf("Exit from program cause ctrl-c, bye bye\n");
exit(EXIT_SUCCESS);
}
My question is how can I found out the thread ids inside the event handler function and is it correct to call pthread_exit or should I use something else?
Don't call pthread_exit() from a signal handler! It is not required to be async-signal-safe, see signal-safety.
In general, you should do as little as possible in a signal handler. The common idiom is to just set a flag that is periodically checked in your main loop like e.g.
volatile sig_atomic_t exitRequested = 0;
void signal_handler(int signum)
{
exitRequested = 1;
}
int main(void)
{
// init and setup signals
while (!exitRequested)
{
// do work
}
// cleanup
}
Also, use sigaction() for installing signal handlers. See signal() for reasons not to use it.
#include <stdio.h>
#include <pthread.h>
#include <signal.h>
sigset_t set;
int sigint_signal = 0;
pthread_t monitor_thread, demo_thread;
pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
void *monitor()
{
while(1)
{
sigwait(&set, NULL);
pthread_mutex_lock(&m);
printf("__SIGINT received__\n");
sigint_signal = 1;
pthread_cancel(demo_thread);
pthread_mutex_unlock(&m);
}
}
void *demo_function(){
while(1){
pthread_mutex_lock(&m);
fprintf(stdout, "__Value of SIGNAL FLAG %d:__\n",sigint_signal);
pthread_mutex_unlock(&m);
}
return NULL;
}
int main(){
sigemptyset(&set);
sigaddset(&set,SIGINT);
pthread_sigmask(SIG_BLOCK,&set,0);
pthread_create(&monitor_thread, 0, monitor, NULL);
pthread_create(&demo_thread, 0, demo_function, NULL);
pthread_join(demo_thread, NULL);
return 0;
}
monitor_thread is the thread that is continuously running to catch the SIGINT signal. On receiving the signal it must cancel the other thread and end.
SIGINT is getting received, this can be verified with the value of the variable sigint_signal which becomes 1 once the signal is received.But pthread_cancel is not getting executed, because once the value of sigint_signal is changed to 1, the demo_thread keeps on running.Please help.
Read the documentation: http://man7.org/linux/man-pages/man3/pthread_cancel.3.html
There you will see that pthread_cancel is not guaranteed to instantly kill the thread, but rather that it depends on the state of that thread. By default, cancellation can only occur at cancellation points, which do include write() which may indirectly include printf().
Anyway, the real solution is to not use pthread_cancel at all, and instead use sigint_signal as the while loop condition in demo_function.
As for why pthread_cancel is a bad idea, this is because in general, functions are usually not written in a way that they are prepared to die. It's hard to reason about resource management in a context where execution might be terminated asynchronously.
I have the program below and I want to use signals to print the every 5 seconds, and handle keyboard interrupt like ctrl + c to terminate the process and ctrl + p to print the result.
int i=1;
while(i>0)
{
i++;
if(i%2==0)
{
printf("%d \n",i)
}
}
In my experience signal handling difficult to do reliably, prone to subtle race conditions and the like (and whoever thought EINTR was a good idea should be shot.) Then again I suppose I never really got the UNIX way of doing things.
My advise is to do as little work as humanly possible inside of the handlers themselves and to try to keep the signals masked anywhere you're not directly interested in them.
The following is my attempt at installing a SIGALRM handler and printing a message every 5 seconds:
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <sys/select.h>
// Raise a flag once the event occurs
volatile sig_atomic_t event;
void handler(int sig) { event = 1; }
int main(void) {
sigset_t mask;
// Install our alarm handler
struct sigaction action = { 0 };
action.sa_handler = handler;
sigaction(SIGALRM, &action, NULL);
// Mask out the alarm signal during normal operation to avoid races
// and having to handle EINTR everywhere
sigemptyset(&mask);
sigaddset(&mask, SIGALRM);
sigprocmask(SIG_SETMASK, &mask, &mask);
// Here goes the main loop..
for(;;) {
// Set the alarm
alarm(5);
// Wait for the alarm to happen with the alarm signal unblocked.
// Add whatever other I/O you're waiting for here
pselect(0, NULL, NULL, NULL, NULL, &mask);
// Did we get woken up by an alarm signal?
if(event) {
event = 0;
puts("Alarm!");
}
}
}
In your specific computationally-bound case I would suggest strategically polling the event flag from the loop instead of attempting to extract and print the present number from within the signal handler.
If you decide to go the latter route then beware that you cannot rely on being able to atomically read and write the value. Instead I would suggest a double-buffering scheme placing the two most recent values in a circular buffer with a (volatile sig_atomic_t) index pointing out the right slot. Oh, and you'll have to do the I/O through manual string manipulation and write() since printf is forbidden in a signal handler. The real kicker, though, is that you won't be able to synchronize with other standard output text in any sane fashion.
In essence using multithreading with a separate calculation thread is a far superior means of achieving the same end.
I'm writing a code in which I have two threads running in parallel.
1st is the main thread which started the 2nd thread.
2nd thread is just a simple thread executing empty while loop.
Now I want to pause / suspend the execution of 2nd thread by 1st thread who created it.
And after some time I want to resume the execution of 2nd thread (by issuing some command or function) from where it was paused / suspended.
This question is not about how to use mutexes, but how to suspend a thread.
In Unix specification there is a thread function called pthread_suspend, and another called pthread_resume_np, but for some reason the people who make Linux, FreeBSD, NetBSD and so on have not implemented these functions.
So to understand it, the functions simply are not there. There are workarounds but unfortunately it is just not the same as calling SuspendThread on windows. You have to do all kinds of non-portable stuff to make a thread stop and start using signals.
Stopping and resuming threads is vital for debuggers and garbage collectors. For example, I have seen a version of Wine which is not able to properly implement the "SuspendThread" function. Thus any windows program using it will not work properly.
I thought that it was possible to do it properly using signals based on the fact that JVM uses this technique of signals for the Garbage collector, but I have also just seen some articles online where people are noticing deadlocks and so on with the JVM, sometimes unreproducable.
So to come around to answer the question, you cannot properly suspend and resume threads with Unix unless you have a nice Unix that implements pthread_suspend_np. Otherwise you are stuck with signals.
The big problem with Signals is when you have about five different libraries all linked in to the same program and all trying to use the same signals at the same time. For this reason I believe that you cannot actually use something like ValGrind and for example, the Boehm GC in one program. At least without major coding at the very lowest levels of userspace.
Another answer to this question could be. Do what Linuz Torvalds does to NVidia, flip the finger at him and get him to implement the two most critical parts missing from Linux. First, pthread_suspend, and second, a dirty bit on memory pages so that proper garbage collectors can be implemented. Start a large petition online and keep flipping that finger. Maybe by the time Windows 20 comes out, they will realise that Suspending and resuming threads, and having dirty bits is actually one of the fundamental reasons Windows and Mac are better than Linux, or any Unix that does not implement pthread_suspend and also a dirty bit on virtual pages, like VirtualAlloc does in Windows.
I do not live in hope. Actually for me I spent a number of years planning my future around building stuff for Linux but have abandoned hope as a reliable thing all seems to hinge on the availability of a dirty bit for virtual memory, and for suspending threads cleanly.
As far as I know you can't really just pause some other thread using pthreads. You have to have something in your 2nd thread that checks for times it should be paused using something like a condition variable. This is the standard way to do this sort of thing.
I tried suspending and resuming thread using signals, here is my solution. Please compile and link with -pthread.
Signal SIGUSR1 suspends the thread by calling pause() and SIGUSR2 resumes the thread.
From the man page of pause:
pause() causes the calling process (or thread) to sleep until a
signal is delivered that either terminates the process or causes the
invocation of a
signal-catching function.
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <signal.h>
// Since I have only 2 threads so using two variables,
// array of bools will be more useful for `n` number of threads.
static int is_th1_ready = 0;
static int is_th2_ready = 0;
static void cb_sig(int signal)
{
switch(signal) {
case SIGUSR1:
pause();
break;
case SIGUSR2:
break;
}
}
static void *thread_job(void *t_id)
{
int i = 0;
struct sigaction act;
pthread_detach(pthread_self());
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
act.sa_handler = cb_sig;
if (sigaction(SIGUSR1, &act, NULL) == -1)
printf("unable to handle siguser1\n");
if (sigaction(SIGUSR2, &act, NULL) == -1)
printf("unable to handle siguser2\n");
if (t_id == (void *)1)
is_th1_ready = 1;
if (t_id == (void *)2)
is_th2_ready = 1;
while (1) {
printf("thread id: %p, counter: %d\n", t_id, i++);
sleep(1);
}
return NULL;
}
int main()
{
int terminate = 0;
int user_input;
pthread_t thread1, thread2;
pthread_create(&thread1, NULL, thread_job, (void *)1);
// Spawned thread2 just to make sure it isn't suspended/paused
// when thread1 received SIGUSR1/SIGUSR2 signal
pthread_create(&thread2, NULL, thread_job, (void *)2);
while (!is_th1_ready && !is_th2_ready);
while (!terminate) {
// to test, I am sensing signals depending on input from STDIN
printf("0: pause thread1, 1: resume thread1, -1: exit\n");
scanf("%d", &user_input);
switch(user_input) {
case -1:
printf("terminating\n");
terminate = 1;
break;
case 0:
printf("raising SIGUSR1 to thread1\n");
pthread_kill(thread1, SIGUSR1);
break;
case 1:
printf("raising SIGUSR2 to thread1\n");
pthread_kill(thread1, SIGUSR2);
break;
}
}
pthread_kill(thread1, SIGKILL);
pthread_kill(thread2, SIGKILL);
return 0;
}
There is no pthread_suspend(), pthread_resume() kind of APIs in POSIX.
Mostly condition variables can be used to control the execution of other threads.
The condition variable mechanism allows threads to suspend execution
and relinquish the processor until some condition is true. A condition
variable must always be associated with a mutex to avoid a race
condition created by one thread preparing to wait and another thread
which may signal the condition before the first thread actually waits
on it resulting in a deadlock.
For more info
Pthreads
Linux Tutorial Posix Threads
If you can use processes instead, you can send job control signals (SIGSTOP / SIGCONT) to the second process. If you still want to share the memory between those processes, you can use SysV shared memory (shmop, shmget, shmctl...).
Even though I haven't tried it myself, it might be possible to use the lower-level clone() syscall to spawn threads that don't share signals. With that, you might be able to send SIGSTOP and SIGCONT to the other thread.
For implementing the pause on a thread, you need to make it wait for some event to happen. Waiting on a spin-lock mutex is CPU cycle wasting. IMHO, this method should not be followed as the CPU cycles could have been used up by other processes/threads.
Wait on a non-blocking descriptor (pipe, socket or some other). Example code for using pipes for inter-thread communication can be seen here
Above solution is useful, if your second thread has more information from multiple sources than just the pause and resume signals. A top-level select/poll/epoll can be used on non-blocking descriptors. You can specify the wait time for select/poll/epoll system calls, and only that much micro-seconds worth of CPU cycles will be wasted.
I mention this solution with forward-thinking that your second thread will have more things or events to handle than just getting paused and resumed. Sorry if it is more detailed than what you asked.
Another simpler approach can be to have a shared boolean variable between these threads.
Main thread is the writer of the variable, 0 - signifies stop. 1 - signifies resume
Second thread only reads the value of the variable. To implement '0' state, use usleep for sime micro-seconds then again check the value. Assuming, few micro-seconds delay is acceptable in your design.
To implement '1' - check the value of the variable after doing certain number of operations.
Otherwise, you can also implement a signal for moving from '1' to '0' state.
You can use mutex to do that, pseudo code would be:
While (true) {
/* pause resume */
lock(my_lock); /* if this is locked by thread1, thread2 will wait until thread1 */
/* unlocks it */
unlock(my_lock); /* unlock so that next iteration thread2 could lock */
/* do actual work here */
}
You can suspend a thread simply by signal
pthread_mutex_t mutex;
static void thread_control_handler(int n, siginfo_t* siginfo, void* sigcontext) {
// wait time out
pthread_mutex_lock(&mutex);
pthread_mutex_unlock(&mutex);
}
// suspend a thread for some time
void thread_suspend(int tid, int time) {
struct sigaction act;
struct sigaction oact;
memset(&act, 0, sizeof(act));
act.sa_sigaction = thread_control_handler;
act.sa_flags = SA_RESTART | SA_SIGINFO | SA_ONSTACK;
sigemptyset(&act.sa_mask);
pthread_mutex_init(&mutex, 0);
if (!sigaction(SIGURG, &act, &oact)) {
pthread_mutex_lock(&mutex);
kill(tid, SIGURG);
sleep(time);
pthread_mutex_unlock(&mutex);
}
}
Not sure if you will like my answer or not. But you can achieve it this way.
If it is a separate process instead of a thread, I have a solution (This might even work for thread, maybe someone can share your thoughts) using signals.
There is no system currently in place to pause or resume the execution of the processes. But surely you can build one.
Steps I would do if I want it in my project:
Register a signal handler for the second process.
Inside the signal handler, wait for a semaphore.
Whenever you want to pause the other process, just send in a signal
that you registered the other process with. The program will go into
sleep state.
When you want to resume the process, you can send a different signal
again. Inside that signal handler, you will check if the semaphore is
locked or not. If it is locked, you will release the semaphore. So
the process 2 will continue its execution.
If you can implement this, please do share your feedack, if it worked for you or not. Thanks.
I have a main application that spawns a seperate thread to process messages off a queue. I have an issue on AIX when I hit CTRL-C as it seems to make some "connection handles" in the thread become invalid. I do have a shutdown hook in the main program catching the SIGINT but on AIX it seems to somehow send a signal to the thread as well...although that is not really possible from what I hear...
Essentially I would like to know if I want the MAIN application to handle ALL signals I am interested in and have the thread/s NEVER handle any signals...is that "good practice"?
If so how can I NOT use "sigwait" in the thread...in fact I do not want any "signal code" in the thread/s...they must simply not receive any signals at all.
I have emptied out all the signals:
sigemptyset(&set);
And have set the SIG_BLOCK
s = pthread_sigmask(SIG_BLOCK, &set, NULL);
So here is a dummy test programe:
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>
#define handle_error_en(en, msg) do { errno = en; perror(msg); exit(EXIT_FAILURE); } while (0)
static void * threadMainLoop(){
//Here I do not want the thread to use "sigwait"....
while(running == TRUE){
//do some thread work and never have any signals come in
}
}
void shutdownHook(int sig){
printf("\nCtrl-C pressed....shutdown hook in main...\n");
}
void signalErrorHandler(int signum){
printf("\nSignal error handler in main...\n");
}
int main(int argc, char *argv[]){
pthread_t thread;
sigset_t set;
int s;
//Catch the following signals in the MAIN thread
(void) signal(SIGINT, shutdownHook);
(void) signal(SIGSEGV, signalErrorHandler);
(void) signal(SIGBUS, signalErrorHandler);
(void) signal(SIGILL, signalErrorHandler);
(void) signal(SIGTERM, signalErrorHandler);
(void) signal(SIGABRT, signalErrorHandler);
sigemptyset(&set); //BLOCK all signals
s = pthread_sigmask(SIG_BLOCK, &set, NULL);
if (s != 0)
handle_error_en(s, "pthread_sigmask");
s = pthread_create(&thread, NULL, &threadMainLoop, (void *) NULL);
if (s != 0)
handle_error_en(s, "pthread_create");
pause();
}
If I just create a thread and have, for example, the SIGINT signal handler in the MAIN thread but do NOT has the SIG_BLOCK set for the thread and the user hits CTRL-C....does the thread get affected at all even though the signal handler in the main thread runs? That seems to be what I am seeing on AIX ;-(
Thanks for the help, much appreciated
Lynton
With s = pthread_sigmask(SIG_BLOCK, &set, NULL); , you're not blocking anything.
Use:
sigfillset(&set);
sets = pthread_sigmask(SIG_SETMASK, &set, NULL);
If you want to block every signal, or explicitly add the signals you want to block to the set if you're using SIG_BLOCK.
After you've created the threads, you need to restore the signal mask, otherwise no threads will catch any signal.
However, looking at your previous question, it might be that the thread catching the signal doesn't handle being interrupted. That is, if you're blocked doing a syscall, and a signal arrives, that syscall gets aborted. Some operating systems defaults to automatically call the system call again, some returns an error and sets errno to EINTR, which the application must handle - and bad things might happen if that's not handled.
Instead, install your signal handlers with sigaction() instead of signal() , and set the SA_RESTART flag, which will cause system calls to automatically restart in case it got aborted by a signal.
Still wrong design.
Do not use CTRL+C to stop an application in a controlled manner.
Use a correctly designed controller app that will be accessible over CORBA, RMI, or some other method to interact with the user and control the background app.
Have fun guys...