Broad Question: What is wrong with my code so that all the signals being generated aren't being caught by the two handler threads?
The unfortunate details for my poor question: I'm supposed to write some code with a main function, 3 generator threads to generate sig1 and sig2 type signals and two signal handling threads. I have tried solving this using the code shown below but I am running into some errors. I tried using sigaction with sigwaitinfo and sigwait to catch signals. But both methods don't seem to work correctly. In the code attached handler1 uses sigaction and sigwaitinfo, handler2 uses sigwait. But I have tried having both handlers use either one and my results are never as I believe they should be. It seems like some signals are never caught. What is wrong with my code so that all the signals aren't being caught? Here is a sample output
Sample Output
signal 1 received
signal 2 received
signal 1 received
signal 2 received
signal 2 received
sigSent1==2,sigSent2==7,sigReceived1==2,sigReceived2==3
A desired output would be
Possible Desired Output
signal 1 received
signal 2 received
signal 1 received
signal 2 received
signal 2 received
signal 1 received
signal 2 received
signal 1 received
signal 2 received
sigSent1==4,sigSent2==5,sigReceived1==4,sigReceived2==5
Sorry if this question is asking a lot but I really have no idea why not all signals are being caught and have been googling around and testing this for like 6 hours today and 3 hours yesterday as well as looking at the man pages...I may be missing something obvious...
#include<semaphore.h>
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<pthread.h>
#include<time.h>
#include<signal.h>
#include<string.h>
#include<math.h>
/*
Pre-definitions of functions
*/
void generator();
void handler1();
void handler2();
void reporter();
/*
Global Variables
*/
int total_signal_count=0;
int sentSignal1=0;
int sentSignal2=0;
int receivedSignal1=0;
int receivedSignal2=0;
sem_t s_lock;
sem_t r_lock;
sigset_t set;
pthread_mutex_t lock;
pthread_t tid[5];
/*
Main function
*/
int main(int argc, char ** argv)
{
int i=0;
int randomNum=0;
int error;
int pid;
sigset_t mask_all,mask_one,prev_one;
//Setting up signals
//Get Random time
time_t now;
time(&now);
//semaphore is initialized to be global and val 1
sem_init(&s_lock,0,1);
sem_init(&r_lock,0,1);
srand((unsigned) time(&now));
//Blakc in main thread
sigemptyset(&set);
sigaddset(&set,SIGUSR1);
sigaddset(&set,SIGUSR2);
pthread_sigmask(SIG_BLOCK,&set,NULL);
pthread_sigmask(SIG_BLOCK,&set,NULL);
//Loops until more threads created than 2
while(i<3)
{ error=pthread_create(&tid[i],NULL,(void*)generator,NULL);
if(error!=0)
{
printf("failed to create thread\n");
}
i++;
}//end while loop
while(i<5)
{
error=pthread_create(&tid[3],NULL,(void*)handler1,NULL);
if(error!=0)
{
printf("failed to create thread\n");
}
error=pthread_create(&tid[4],NULL,(void*)handler2,NULL);
if(error!=0)
{
printf("failed to create thread \n");
}
i++;
}
//join the threads so main won't return
i=0;
int returnVal;
sleep(10);
printf("\n sigSent1==%d,sigSent2==%d,sigReceived1==%d,sigReceived2==%d\n",sentSignal1,sentSignal2,receivedSignal1,receivedSignal2);
while(i<5)//Loops until threads are joined
{
// printf("gonna join %d\n",i);
pthread_join(tid[i],NULL);
/*if((returnVal=pthread_join(tid[i],(void**)&returnVal))!=0)
{
printf("Error joining thread: %s at %d\n", strerror(returnVal),i);
}*/
i++;
}//end while
return 0;
}//end of main function
/*
Generator threads
*/
void generator()
{
sleep(1);
int i=3;
int randomNum=0;
int val=0;
int total_signal_c=9997;
while(total_signal_c<10000)
{
usleep(1);
//Randomly select to generate SIGUSR1 or SIGUSR2
//Use pthread_kill(tid,SIGUSR1/SIGUSR2) to send the signal to a thread
// printf("total_signal_count%d\n",total_signal_c);
//Create either a sig1 signal or sig2 signal
randomNum=rand()%2;
switch(randomNum)
{
case 0:
val=pthread_kill(tid[3],SIGUSR1);
if(val!=0)
{
printf("kill fail ==%d\n",val);
}
sem_wait(&s_lock);
//semaphore
//mutex
sentSignal1++;
sem_post(&s_lock);
break;
case 1:
val=pthread_kill(tid[4],SIGUSR2);
if(val!=0)
{
printf("kill fail2\n");
}
sem_wait(&s_lock);
sentSignal2++;
sem_post(&s_lock);
//
//
break;
}
i++;
total_signal_c++;
//delay for a random time, 0.01 to 0.1 second
}
}
/*
Handler 1 threads
*/
void handler1()
{
//Setting up signals
// printf("In handler1\n");
struct sigaction s;
siginfo_t info;
sigemptyset(&s.sa_mask);
//use signal to perma block for handler2
signal(SIGUSR2,handler1);
//Add Sigusr1 to set
sigaddset((&s.sa_mask),SIGUSR1);
pthread_sigmask(SIG_BLOCK,&s.sa_mask,NULL);
int val=-1;
//use signal(), sigaddset(), pthread_sigmask() etc to block and unblock signals as required.
while(1)
{ //use sigwaitinfo(); to receive a signal
val=-1;
val=sigwaitinfo(&s.sa_mask,&info);
//if signal received modify the corresponding counter
if(info.si_signo==SIGUSR1){
//increment semaphore lock
sem_wait(&r_lock);
receivedSignal1++;
//decrement semaphore lock
sem_post(&r_lock);
printf("signal 1 received\n");
}
if(val==-1)
{
// break;
}
}
pthread_exit(NULL);
}
/*
Handler2 threads
*/
void handler2()
{
int sigInfo=0;
//use signal to perma block for handler2
signal(SIGUSR1,handler2);
int val=-1;
while(1)
{ //use sigwaitinfo(); to receive a signal
val=-1;
val=sigwait(&set,&sigInfo);
//if signal received modify the corresponding counter
if(sigInfo==SIGUSR2){
//increment semaphore lock
sem_wait(&r_lock);
receivedSignal2++;
//decrement semaphore lock
sem_post(&r_lock);
printf("signal 2 received\n");
}
}
pthread_exit(NULL);
}
Some signals can be losts when there is a pending signal with he same code. From the specification of sigaction:
If a subsequent occurrence of a pending signal is generated, it is implementation-dependent as to whether the signal is delivered or accepted more than once in circumstances other than those in which queueing is required under the Realtime Signals Extension option. The order in which multiple, simultaneously pending signals outside the range SIGRTMIN to SIGRTMAX are delivered to or accepted by a process is unspecified.
If you want to catch all the signals you have two solutions:
Use real-time signals with a value from SIGRTMIN to SIGRTMAX, instead of SIGUSR1 and SIGUSR2. Both pthread_sigqueue() and pthread_kill() will fail to send the signal if SIGQUEUE_MAX signals are pending or if the system hasn't enough resources to queue the signal.
Wait the precedent signal has been caught before to send another one.
EDIT:
1. Some explainations to answer your last comment.
You can't block-only a signal using signal(), you can ignore it (using SIG_IGN instead of a handler function) or register a handler function. With a handler function, I think we can say the signal is blocked AND caught.
I think your t.a. want you to handle one type of signal, for exemple SIGUSR1, using signal() and a handler function, and to handle SIGUSR2 with a thread using sigwaitinfo().
Using signal() you don't need to block the signals that you want to catch, and it can be done in the main thread.
Using sigwaitinfo() you need to block the signal you want to catch at least in the thread that will receive it.
You can have a look to the source code I have pasted at the end of this post.
2. More precisions.
To block a signal without placing an automatic catch/handler function, you have to use sigprocmask() in a single-threaded program, or pthread_sigmask() in a multi-threaded program. You also can use sigaction() in order to block some incomming signals during the execution of a signal handler function.
About signal catching, there are two ways to catch a signal:
A signal handler function is registered with signal() (or sigaction()) and automatically called when the signal is received, unless the signal was blocked in all threads. In order to make signal() work, you have to let at least one thread that non block the signal. You haven't to use sigwait() to handle the signal, because the program will automatically wait in parallel of its execution.
Using signal() will create a signal context when the signal is received and you will have to use async-signal-safe functions in the signal handler function. signal() register a handler function for the whole process, not only for the calling thread.
A handling thread need to catch the signals with sigwait() or sigwaitinfo(), and these threads aren't restricted to async-signal-safe functions. The signals to catch must be blocked using pthread_sigmask() at least in the thread that is the target of pthread_kill().
And must be blocked in all threads in order to catch process-wide signals for example triggered with kill() (if at least one thread doesn't block the signal, then it will have the default effect on the process).
3. Some explanations on what your program is doing.
In the main thread, the signals SIGUSR1 and SIGUSR2 are blocked, so all the threads created by the main thread after this blocking will have these signals blocked, because they inherits of the mask of the creating thread.
When you call signal() it will register the functions handler1() and handler2() as signal handling functions to be called when a thread receive the signals. But these signals are blocked for all the threads, so handler1() and handler2() won't be called as signal handler functions. So, using signal() in your program is useless.
Moreover, handler1() and handler2() are designed to be handling threads, not signal handler functions. So you shouldn't register them with signal(), you have to register non-thread functions.
You should increment the counters for sent signals only when pthread_kill() didn't failed.
When creating the handling threads, the program create 2 useless threads, because the loop is executed for i = 3 and i = 4, and you create 2 threads in this loop. So the correct code is while(i < 4), or better remove the loop.
4. I modified your program in order to catch SIGUSR1 using signal():
You will see it only needs to block SIGUSR2 in handler2_thread(). No other blocking are needed in the program.
In this code, you will see the difference between a handling thread and a signal handler function, the signals received by thread1 are handled by the signal handler function handler1_func(), while the signals receveid by handler2_thread are handled in the thread itself.
The variable receivedSignal1_flag is declared volatile and of type sig_atomic_t because there is a race condition on it between the thread that check and reset it and the handler function that set it to 1. Using this way, some caught signals won't be counted. Regarding what I have read on sig_atomic_t, I'm not sure if it is possible to increment the counter receivedSignal1 directly in handler1_func() because the increment operation isn't atomic, and so can be disturbed by another signal handler. But maybe it is possible if handler_func() is the only one signal handler to read and write receivedSignal1 and having declared it volatile and sig_atomic_t. Also note that receivedSignal1_flag isn't locked with a semaphore nor a mutex, because only one thread is using it.
#include<semaphore.h>
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<pthread.h>
#include<time.h>
#include<signal.h>
#include<string.h>
#include<math.h>
/*
Pre-definitions of functions
*/
void generator();
void handler1_func(int);
void thread1();
void handler2_thread();
void reporter();
/*
Global Variables
*/
int total_signal_count=0;
int sentSignal1=0;
int sentSignal2=0;
///////////////////////////////////////
//
// receivedSignal1_flag is volatile and
// sig_atomic_t because there is a race
// condition on it (used in the signal
// handler, and in the thread).
//
///////////////////////////////////////
volatile sig_atomic_t receivedSignal1_flag;
int receivedSignal1=0;
int receivedSignal2=0;
sem_t s_lock;
sem_t r_lock;
pthread_mutex_t lock;
pthread_t tid[5];
/*
Main function
*/
int main(int argc, char ** argv)
{
int i=0;
int randomNum=0;
int error;
int pid;
sigset_t mask_all,mask_one,prev_one;
//Setting up signals
//Get Random time
time_t now;
time(&now);
//semaphore is initialized to be global and val 1
sem_init(&s_lock,0,1);
sem_init(&r_lock,0,1);
srand((unsigned) time(&now));
//Loops until more threads created than 2
while(i<3)
{ error=pthread_create(&tid[i],NULL,(void*)generator,NULL);
if(error!=0)
{
printf("failed to create thread\n");
}
i++;
}//end while loop
error=pthread_create(&tid[3],NULL,(void*)thread1,NULL);
if(error!=0)
{
printf("failed to create thread\n");
}
error=pthread_create(&tid[4],NULL,(void*)handler2_thread,NULL);
if(error!=0)
{
printf("failed to create thread \n");
}
//join the threads so main won't return
i=0;
int returnVal;
sleep(15);
printf("\n sigSent1==%d,sigSent2==%d,sigReceived1==%d,sigReceived2==%d\n",sentSignal1,sentSignal2,receivedSignal1,receivedSignal2);
while(i<5)//Loops until threads are joined
{
// printf("gonna join %d\n",i);
pthread_join(tid[i],NULL);
/*if((returnVal=pthread_join(tid[i],(void**)&returnVal))!=0)
{
printf("Error joining thread: %s at %d\n", strerror(returnVal),i);
}*/
i++;
}//end while
return 0;
}//end of main function
/*
Generator threads
*/
void generator()
{
sleep(5);
int i=3;
int randomNum=0;
int val=0;
int total_signal_c=9990;
while(total_signal_c<10000)
{
usleep(1);
//Randomly select to generate SIGUSR1 or SIGUSR2
//Use pthread_kill(tid,SIGUSR1/SIGUSR2) to send the signal to a thread
// printf("total_signal_count%d\n",total_signal_c);
//Create either a sig1 signal or sig2 signal
randomNum=rand()%2;
switch(randomNum)
{
case 0:
/////////////////////////////////////////
// Send SIGUSR1 to thread1
/////////////////////////////////////////
val=pthread_kill(tid[3],SIGUSR1);
if(val!=0)
{
printf("\nkill fail ==%d",val);
} else {
sem_wait(&s_lock);
//semaphore
//mutex
sentSignal1++;
sem_post(&s_lock);
}
break;
case 1:
/////////////////////////////////////////
// Send SIGUSR2 to handler2_thread
/////////////////////////////////////////
val=pthread_kill(tid[4],SIGUSR2);
if(val!=0)
{
printf("\nkill fail2");
} else {
sem_wait(&s_lock);
sentSignal2++;
sem_post(&s_lock);
//
//
}
break;
}
i++;
total_signal_c++;
//delay for a random time, 0.01 to 0.1 second
}
}
//////////////////////////////////////////
//
// Signal handler function for SIGUSR1:
//
//////////////////////////////////////////
void handler1_func(int signo)
{
// write on stdout using an async-signal-safe function:
write(STDOUT_FILENO,"\nSignal handler function: SIGUSR1 caught\n",41);
// set the received signal flag to 1:
if(signo == SIGUSR1) receivedSignal1_flag = 1;
}
/////////////////////////////////////////////////////////////
//
// The thread that will receive SIGUSR1 but not handle it
// because handler1_func() will handle it automatically:
//
/////////////////////////////////////////////////////////////
void thread1()
{
//////////////////////////////////////////////
//
// register handler1_func() as signal handler
// for the whole process, not only the thread.
// It means that if another thread doesn't
// block SIGUSR1 and receive it, then
// handler1_func() will also be called:
//
//////////////////////////////////////////////
signal(SIGUSR1,handler1_func);
while(1)
{
///////////////////////////////////////////////////
// If a signal has been handled by handler1_func()
// then receivedSignal1_flag = 1.
// And so increment receivedSignal1 and print.
///////////////////////////////////////////////////
if(receivedSignal1_flag == 1) {
// reset the flag:
receivedSignal1_flag = 0;
sem_wait(&r_lock);
receivedSignal1++;
printf("\nThread1: SIGUSR1 received and handled by handler1_func()\n");
sem_post(&r_lock);
}
}
pthread_exit(NULL);
}
////////////////////////////////////////
//
// Handling thread for SIGUSR2:
//
////////////////////////////////////////
void handler2_thread()
{
///////////////////////////////////////////////
//
// Need to block SIGUSR2 in order to avoid
// the default handler to be called.
//
///////////////////////////////////////////////
sigset_t set;
sigemptyset(&set);
sigaddset(&set,SIGUSR2);
pthread_sigmask(SIG_BLOCK,&set,NULL);
siginfo_t info;
int val=-1;
while(1)
{
val=-1;
val=sigwaitinfo(&set,&info);
//if signal received modify the corresponding counter
if(info.si_signo==SIGUSR2){
//increment semaphore lock
sem_wait(&r_lock);
receivedSignal2++;
//decrement semaphore lock
printf("\nhandler2_thread: signal 2 received\n");
sem_post(&r_lock);
}
}
pthread_exit(NULL);
}
Only async-signal-safe functions may be safely called from a signal handler. sigwait() and sigwaitinfo() are not async-signal-safe. See 2.4 Signal Concepts at http://pubs.opengroup.org/onlinepubs/9699919799/functions/V2_chap02.html. Also see the Linux signal.7 man page. Nor is printf() async-signal-safe.
Calling pthread_exit() in a signal handler is undefined behavior. It will terminate the thread - but in a signal-handling context, potentially causing significant issues. The following questions just begin to touch on the problems that making a call to pthread_exit() in a signal handler cause: pthread_exit() in signal handler and How to properly terminate a thread in a signal handler? See also http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_exit.html
Fundamentally, your code is confused. You start handler1() and handler2() as separate threads, then register those same functions as signal handlers, and then call sigwait()/sigwaitinfo() within the functions.
Given the way the code combines threads, signal handlers, while(1)... loops, it's pretty much impossible to even begin to guess what's happening. You may be getting threads that spawn signal handlers that get stuck in infinite loops, for example.
This line of code:
signal(SIGUSR1,handler2);
means that when SIGUSR1 is received, handler2() will be called in a signal context - but handler2() has a while(1) loop in it...
Asynchronous signal processing is a difficult concept to grasp. I'd say you need to start with something much simpler than multiple threads trying to signal each other.
Related
I got this issue:
I made a program in c, where the main process creates some child process, and these, after a while, are able to send a signal to the main process:
the signal is sent with this code:
kill(getppid(), SIGUSR1);
and the main process, in the while loop is waiting the SIGUSR1 message...
everything is fine, but if I increase the child number and automatically the possibility to have more signals in the same time, the program crash printing the message:
User defined signal 1
the main code is like this:
void signalHandler(int sig, siginfo_t* info, void* vp) {
if (sig == SIGUSR1) {
printf("SIGUSR1 has arrived\n");
} else if (sig == SIGUSR2) {
printf("SIGUSR2 has arrived\n");
}
}
int main(int argc, char const *argv[]) {
struct sigaction action, old_action;
memset(&action, 0, sizeof(struct sigaction));
action.sa_sigaction = signalHandler;
sigemptyset(&action.sa_mask);
action.sa_flags = SA_RESTART | SA_NODEFER;
while (1) {
sigaction(SIGUSR1, &action, &old_action);
sigaction(SIGUSR2, &action, &old_action);
}
}
I think the problem is that the signal is sent when the master is still working on the previous signal...but how can I do to fix this thing
thank you very much
It means that the child is sending the signal before the parent process was able to call sigaction() to configure the signal handler. When this happens, the default signal reaction to SIGUSR1 terminates the program:
SIGUSR1 P1990 Term User-defined signal 1
https://man7.org/linux/man-pages/man7/signal.7.html
However, there are many problems with your code. printf() is not safe to be called inside a signal handler (it's AS-Unsafe as defined by POSIX):
https://pubs.opengroup.org/onlinepubs/9699919799.2018edition/functions/V2_chap02.html#tag_15_04_03
Also, using SA_NODEFER may create nested signals (another signal handler is called while some signal handler is running) but your program does not protect against a flood. Given enough children this will generate a stack overflow. Finally, the main program keeps running a non-stop infinite loop reconfiguring the signals, while it should have configured them only once outside the loop and blocked inside the loop (for example sigwait() or pselect()):
https://man7.org/linux/man-pages/man2/select.2.html
Finally, if you expect to run a large number of children that might flood the parent with signals, then it would be better to use the real time signal generation function (sigqueue()) rather than kill(). The difference is that with sigqueue(), all signals are queued and SA_NODEFER is not necessary to avoid discarding signals while some other signal handler is running:
https://pubs.opengroup.org/onlinepubs/9699919799.2018edition/functions/V2_chap02.html#tag_15_04_02
Final conclusion: the code should be completely rewritten.
I want use signal (SIGUSR1) to sync process in C. I want that parent process wainting for a signal, when receive this signal, send the same signal to child process. I wrote a short paragraph to stimulate reasoning, but it does not go away.
#include <sys/types.h>
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
void trataSIGUSR1(int sigNum) {
printf("SIGUSR1\n");
}
int main(void) {
pid_t pid;
struct sigaction sa;
pid = fork();
if (pid == 0) {
struct sigaction sa = {0};
sa.sa_handler = trataSIGUSR1;
sa.sa_flags = 0;
sigemptyset(&sa.sa_mask);
sigaction(SIGUSR1,&sa,NULL);
pause();
printf("This never execute");
} else {
printf("I'am father: %d!\n",getppid());
kill(0,SIGUSR1);
pause();
}
}
OUTPUT
I'am father: 12082!
User defined signal 1: 30
Simple hint is use pause() and kill() i.e pause() is for block the process execution until any signal received, once signal received then do_something() and kill() is for sending the SIGUSR1 signal.
Also when you use pause(), it will suspend the process until it received any signal and for that signal default action should be user defined ISR. from manual page of pause()
RETURN VALUE
pause() returns only when a signal was caught and the signal-catching function returned.
In this case pause() returns -1, and errno is set to EINTR.
Here is the sample required example code
//int nSIGINT = 0; /* declare variable of type volatile sigatomic_t */
volatile sigatomic_t nSIGINT;
void trataSIGINT(int sigNum) {
nSIGINT = 1;/* set the flag as needed */
}
int main(void ){
int pid;
pid=fork();/* create child process */
if(pid==0) {
//signal(SIGUSR1,trataSIGINT);/* instead of signal() use sigaction */
struct sigaction sa = {0}; /* initialize sa or fill all its members*/
sa.sa_handler = trataSIGINT;/* set the handler to trataSIGINT*/
sa.sa_flags = 0;
sigemptyset(&sa.sa_mask);
sigaction(SIGUSR1,&sa,NULL); /* when child received SIGUSR1, trataSIGINT gets called */
pause(); /* wait until any signal received */
/* do_something_child() code, this you want to run only after receiving signal */
}
else {
/* do_something_parent() */
printf("parent about to send user signal to child\n");
kill(pid,SIGUSR1); /*send SIGUSR1 to child */
wait(0); /* wait till child completes */
}
return 0;
}
Side note, for setting a flag in trataSIGINT() when SIGUSR1 received, instead of declaring int nSIGINT = 0; declare flag variable as type of volatile sigatomic_t type.
From ISO/IEC 9899:2011 §7.14.1.1 The signal function
¶5 If the signal occurs other than as the result of calling the abort or
raise function, the behavior is undefined if the signal handler
refers to any object with static or thread storage duration that is
not a lock-free atomic object other than by assigning a value to an
object declared as volatile sig_atomic_t, or the signal handler
calls any function in the standard library other than the abort
function, the _Exit function, the quick_exit function, or the
signal function with the first argument equal to the signal number
corresponding to the signal that caused the invocation of the handler.
Furthermore, if such a call to the signal function results in a
SIG_ERR return, the value of errno is indeterminate.252)
252) If any signal is generated by an asynchronous signal handler, the
behavior is undefined.
I'm trying to build a basic program which has 2/3 threads. The main thread, signaler thread, and receiver thread. I'm trying to make it so the main thread starts both a signaler and receiver thread. The signaler thread is then supposed to send 10 SIGUSR1 signals to the receiver thread and increase a global counter. The receiver thread is supposed to receive the 10 signals while increasing its own counter for each signal received.
The trouble I'm having is with joining the threads back together at the end, specifically joining the receiver thread. The majority of the time the program stalls if I try to join them back together, I assume because the receiver thread hasn't finished its job (maybe it has missed signals?) and so it never finishes. I thought maybe this was the case, so I introduced a wait command in the signaler thread to slow it down, but that didn't change anything.
If I comment out the pthread_join(receiver, NULL) then the program runs, but it only catches one signal most of the time. I assume this is because the receiver thread isn't getting much time to run. (although sometimes it catches various amounts, depending on when it was preempted?)
Leaving the pthread_join(receiver, NULL) in the program makes it stall 19/20 times, but that 1/20 time the program returns 10 signals sent and 10 received. This leads me to believe it has something to do with preemption, but I don't understand why it would ever stall in the first place.
Also right now I just have the receiver thread receiving threads while the received counter is < 10. Ideally I would just want to leave it in while(1) loop, but then again I don't know how to join that back into the main thread without freezing everything.
If someone could help me figure out why signals are being missed / why the program is freezing I would be most grateful. I have a suspicion that I'm not setting up the signal mask correctly for the receiver, but I don't know how else I am supposed to do it. Here is the code:
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <signal.h>
void *receivetest(void *args);
void *signaltest(void *args);
int received = 0;
int sent = 0;
pthread_t signaler;
pthread_t receiver;
sigset_t mask;
int main(){
//setting up the signal mask
sigemptyset(&mask);
sigaddset(&mask, SIGUSR1);
//creation of both threads
pthread_create(&receiver, NULL, receivetest, NULL);
pthread_create(&signaler, NULL, signaltest, NULL);
pthread_join(signaler, NULL);
pthread_join(receiver, NULL);
//printing results after joining them back
printf("I'm the main function\n");
printf("Receieved: %d, sent: %d\n", received, sent);
}
void *signaltest(void *args){
int i = 0;
for(i=0;i<10;i++){ //sends 10 signals to receiver thread
pthread_kill(receiver, SIGUSR1);
sent++;
}
}
void *receivetest(void *args){
int c; //sigwait needs int
pthread_sigmask(SIG_BLOCK, &mask, NULL); //sets up the signal mask for this thread
while(received < 10){ //waits for 10 signals and increments receieved
sigwait(&mask, &c);
received++;
}
}
Signals just don't work that way. If a thread receives a signal while that same signal is already pending, nothing happens. Please use an appropriate inter-thread communication method, not signals.
You almost got it right. It is recommended to block the signals from the main thread to protect all new threads from mishandling the signal.
Any thread created after pthread_sigmask(), inherits the sigmask. The first parameter tells pthread_sigmask() what to do with the signals listed in the second parameter.
This line pthread_sigmask(SIG_BLOCK, &mask, NULL) should be placed in the main thread, not on the signal handler. Your original code will work too, but if the signal is sent to the wrong thread, it will kill the whole process.
In addition, the sender is sending signal faster than the receiver can handle. By sleeping for 1 second between each iteration, the receiver will be able to catch up.
I took the liberty and modified your code. I added some prints within the sender and receiver so you'll know what it is doing.
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
void receivetest(void); //function does not return anything
void signaltest(void); // does not accept parameter either.
int received = 0;
int sent = 0;
pthread_t signaler;
pthread_t receiver;
sigset_t mask;
int main(){
//setting up the signal mask
sigemptyset(&mask);
sigaddset(&mask, SIGUSR1);
pthread_sigmask(SIG_BLOCK, &mask, NULL); //sets up the signal mask for this thread
//creation of both threads
pthread_create(&receiver, NULL, (void *)receivetest, NULL);
pthread_create(&signaler, NULL, (void *)signaltest, NULL);
pthread_join(signaler, NULL);
pthread_join(receiver, NULL);
//printing results after joining them back
printf("I'm the main function\n");
printf("Receieved: %d, sent: %d\n", received, sent);
return 0;
}
void signaltest(void){
int i = 0;
for(i=0;i<10;i++){ //sends 10 signals to receiver thread
printf("Sending signal\n");
pthread_kill(receiver, SIGUSR1);
sleep(1); // Don't send signals too fast
sent++;
}
}
void receivetest(void){
int c; //sigwait needs int
while(received < 10){ //waits for 10 signals and increments receieved
sigwait(&mask, &c);
printf("Signal received\n");
received++;
}
}
Output:
Sending signal
Signal received
Sending signal
Signal received
Sending signal
Signal received
Sending signal
Signal received
Sending signal
Signal received
Sending signal
Signal received
Sending signal
Signal received
Sending signal
Signal received
Sending signal
Signal received
Sending signal
Signal received
I'm the main function
Receieved: 10, sent: 10
I have written a code where I have created two child threads from the parent thread.
Then, with receiving a signal from another terminal inside those child threads, I printed the threadID and exited the thread.
I have 2 questions.
I'm receiving the signal from the child thread. Why is it printing the threadID of the parent thread?
After killing the parent thread, how can be the child threads alive??
The Code :
void sig_handler(int signo)
{
if (signo == 1){
printf("%d\n", pthread_self());
pthread_exit(NULL);
}
}
void* doSomeThing(void* arg)
{
printf("In function -> %d\n", pthread_self());
if (signal(1, sig_handler) == SIG_ERR)
printf("\ncan't catch SIGHUP\n");
while(1)
sleep(1);
return NULL;
}
int main(int argc, char *argv[])
{
printf("In function -> %d\n", pthread_self());
char *ch1;
pthread_t tid1, tid2;
ch1 = "random";
int ret1, ret2;
ret1 = pthread_create(&tid1, NULL, &doSomeThing, (void *) ch1 );
ret2 = pthread_create(&tid2, NULL, &doSomeThing, (void *) ch1 );
while(1)
sleep(1);
return 0;
}
Here is the image of the output given in terminal :
The first 3 lines are the 3 threadIDs. 1st one is the Main threadIDs, then the two secondary threads.
Then the threadIDs printed from the following block of code.
if (signo == 1){
printf("%d\n", pthread_self());
pthread_exit(NULL);
}
Why is this happening???
Signals are delivered to the process, not to individual threads. So, you can't have a signal handler just for one thread as you are doing here.
What you can do is block signals you are interested in using pthread_sigmask() and let a dedicated thread handle signals using sigwait(), which is the most common way.
In addition, you can only safely call async-signal-safe functions from within a signal handler. From the Linux signal man page:
Async-signal-safe functions
A signal handler function must be very careful, since processing
elsewhere may be interrupted at some arbitrary point in the execution
of the program. POSIX has the concept of "safe function". If a
signal interrupts the execution of an unsafe function, and handler
either calls an unsafe function or handler terminates via a call to
longjmp() or siglongjmp() and the program subsequently calls an
unsafe function, then the behavior of the program is undefined.
The linked man page has a list of functions that are safe to call from within a signal handler. If the function is not on that list, it is unsafe to call it. No exceptions.
Note that neither printf() nor pthread_exit() are on the list of async-signal-safe functions.
And calling pthread_exit() from within a signal handler creates several other problems:
The thread that exits is generally not under any control. In many cases, the signal can be delivered to any thread.
The exiting thread can leave objects in an unknown state - a mutex can be left locked by a thread that no longer exists, for example.
Any thread cleanup handlers registered with pthread_cleanup_push() will also be called from within a signal handler context.
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
}
}