Signal receiver threads in C and pthread_join stalling program - c

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

Related

Linux - Why is a blocked and ignored signal pending?

When sending a signal to a process that both blocks and ignores it, the kernel still keeps this signal in the pending list (my terminology here). In this case the kernel behaves like the signal is only blocked, although it should also be ignored. I can't understand this behavior. Here is a C code for example with SIGUSR1 (which has the index 10):
#define _GNU_SOURCE
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
void handler(int sig)
{
printf("Received signal %d\n", sig);
}
int main(int argc, char *argv[])
{
printf("PID is %ld\n", (long) getpid());
int sig = SIGUSR1;
//creating the sigaction struct and setting the handler
struct sigaction act;
act.sa_handler = handler;
sigemptyset(&act.sa_mask);
if(sigaction(sig, &act, NULL) == -1)
{
printf("Error: sigaction\n");
exit(1);
}
//Blocking the signal
sigset_t blockedSignals;
sigemptyset(&blockedSignals);
sigaddset(&blockedSignals, sig);
printf("Blocking signal %d\n", sig);
if(sigprocmask(SIG_SETMASK, &blockedSignals, NULL) == -1)
{
printf("Error: sigprocmask\n");
exit(1);
}
//Ignoring the signal
act.sa_handler = SIG_IGN;
printf("Ignoring signal %d\n", sig);
if(sigaction(sig, &act, NULL) == -1)
{
printf("Error: sigaction\n");
exit(1);
}
//Sleeping for a while in order to give the user a chance to send the signal to this process
printf("Sleeping for 20 sec. Please send the signal.\n");
sleep(20);
//Unblocking the signal
/*sigemptyset(&blockedSignals);
printf("Unblocking signal %d\n", sig);
if(sigprocmask(SIG_SETMASK, &blockedSignals, NULL) == -1)
{
printf("Error: sigprocmask\n");
exit(1);
}*/
//Let's check the pending list
sigset_t pendingSignals;
sigemptyset(&pendingSignals);
if(sigpending(&pendingSignals) == -1)
{
printf("Error: sigpending\n");
exit(1);
}
if(sigismember(&pendingSignals, sig) == 1)
{
printf("Signal %d is pending.\n", sig);
}
else
{
printf("Signal %d isn't pending.\n", sig);
}
exit(0);
}
SIGUSR1 is both blocked and ignored. While this process sleeps, if I send a SIGUSR1 to it (from shell: kill -s SIGUSR1 PID), and then checks the pending list, I get this printing:
Signal 10 is pending.
If I uncomment the commented block of code, which unblocks the signal:
sigemptyset(&blockedSignals);
printf("Unblocking signal %d\n", sig);
if(sigprocmask(SIG_SETMASK, &blockedSignals, NULL) == -1)
{
printf("Error: sigprocmask\n");
exit(1);
}
and repeat the experiment, I see the following printing:
Signal 10 isn't pending.
It's like the kernel gives priority to the 'blocking' over the 'ignoring'.
Is it really the case?
Update: As far as I understand, when the process ignores a signal, it means that the kernel won't send it to the process. This also means that it won't keep it in the pending list. For example, if a signal is only blocked by the process, and exists in the pending list, and then we call 'sigaction' in order to ignore it, the kernel will remove this signal from the pending list. So the question is, why if we block+ignore in ahead, the kernel inserts the signal to its pending list?
Blocking a signal and ignoring it are two separate and independent things.
Ignoring a signal by setting its disposition to SIG_IGN instructs that when the signal is delivered the resulting action should be to do nothing.
Blocking a signal (by setting a signal mask that includes that signal) has the effect of preventing that signal from being delivered at all. If it is received, then it will remain pending until unblocked or the process terminates. Signal disposition does not matter until the signal is actually delivered. So,
It's like the kernel gives priority to the 'blocking' over the 'ignoring'. Is it really the case?
Yes. The effect of ignoring a signal cannot be realized while that signal is blocked.
With regard to the update to the question:
As far as I understand, when the process ignores a signal, it means
that the kernel won't send it to the process.
No, that's incorrect. SIG_IGN is a signal disposition. That's what the process does in response to a signal. It can't respond if the kernel doesn't send the signal in the first place.
Note that another option for signal disposition is for the process to run a custom signal handler function. It should be clearer that this is something that the process must do, not something that the kernel does for it.
This also means that it
won't keep it in the pending list.
It would mean that ignored signals never became pending, but your understanding of the semantics is incorrect.
So the question is, why if we
block+ignore from ahead, the kernel inserts the signal to its pending
list?
Because that's what the kernel does with signals. You can characterize it as what the kernel does with all signals, but those that aren't blocked don't stay pending very long.

How to use SIGINT for threads C

I am trying to use SIGINT (CNTRL C) for threads but it is having a weird behavior. I am trying to have a SIGINT function for the thread creator process and a SIGINT function for the threads themselves. Here is a sample code of what I am trying to achieve:
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <semaphore.h>
#include <unistd.h>
#include <pthread.h>
#include <signal.h>
pthread_t *cars;
void carEnd(){
printf("Car from team %ld killed.\n",(long)getpid());
pthread_exit(NULL);
}
void teamEnd(int signum){
for(int j=0; j<3; j++){
pthread_join(cars[j],NULL);
}
printf("Team %ld killed\n",(long)getpid());
exit(0);
}
void *carThread(void* team_number){
signal(SIGINT, carEnd);
sleep(10);
pthread_exit(NULL);
return NULL;
}
int main(){
signal(SIGINT, teamEnd);
int workerId[3];
pthread_t cars[3];
//Create the car threads
for(int i=0; i<3;i++){
workerId[i] = i+1;
pthread_create(&cars[i], NULL, carThread,&workerId[i]);
}
//Waits for all the cars to die
for(int j=0; 3; j++){
pthread_join(cars[j],NULL);
}
return 0;
}
`
After executing, if no SIGINT is detected the program closes after 10 seconds. If a SIGINT is detected, then a single message "Car from team ... killed" appears on the terminal. Would appreciate if anyone could explain me this behavior and how I can fix it to achieve my goal!
A Ctrl-C instructs your terminal to send a SIGINT to the foreground process group, meaning a SIGINT is generated for each process of the foreground group.
When a signal is generated for a process, the system attempts to deliver it to one and only one thread of that process. In your example, all of your threads are eligible to receive the signal, since none have masked ("blocked") the signal as by pthread_sigmask. The system will choose one of the threads for signal delivery.
When the SIGINT is delivered to a thread, some action, known as the signal disposition, is taken. Importantly, a process can have one and only one disposition per signal at any given time — the most recent call to signal() or sigaction determines the disposition. So, your main() thread's chosen SIGINT disposition of teamEnd() is overwritten by the first of your carThread() threads to call signal(), and then redundantly overwritten by the rest of them.
In your case, the SIGINT happens to interrupt a carThread() during its sleep(), printing the message you see, and waking the thread which then terminates.
Beyond the above, I cannot really say what you should do. I think your goal is to gracefully terminate all threads upon SIGINT. If that's so, I'd suggest you do that by forcing the signal to be delivered to main(), and then having that thread instruct the others to quit via some shared flag or condition variable.

Multi Threaded Signal Handling in C on Linux

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.

Which thread handles the signal?

I have 2 threads(thread1 and thread2). And I have signal disposition for SIGINT. Whenever SIGINT occurs thread 2 should handle the signal. For that I wrote below program
void sig_hand(int no) //signal handler
{
printf("handler executing...\n");
getchar();
}
void* thread1(void *arg1) //thread1
{
while(1) {
printf("thread1 active\n");
sleep(1);
}
}
void * thread2(void * arg2) //thread2
{
signal(2, sig_hand);
while(1) {
printf("thread2 active\n");
sleep(3);
}
}
int main()
{
pthread_t t1;
pthread_t t1;
pthread_create(&t1, NULL, thread1, NULL);
pthread_create(&t2, NULL, thread2, NULL);
while(1);
}
I compiled and and run the program. for every 1 second "thread1 active" is printing and for every 3 seconds "thread2 active" is printing.
Now I generated SIGINT. But its printing "thread1 active" and "thread2 active" messages like above. Again I generated SIGINT, now for every 3 seconds only "thread2 active" message is printing. Again I generated SIGINT, now all threads are blocked.
So I understood, for first time main thread executing signal handler. For second time thread1 executing handler and lastly thread2 executing signal handler.
How I can write the code like whenever signal occurs, only thread2 have to execute my signal handler?
If you send a signal to a process, which thread in the process will handle this signal is undetermined.
According to pthread(7):
POSIX.1 also requires that threads share a range of other attributes (i.e., these attributes are process-wide rather than per-thread):
...
- signal dispositions
...
POSIX.1 distinguishes the notions of signals that are directed to the process as a whole and signals that are directed to individual threads. According to POSIX.1, a process-directed signal (sent using kill(2), for example) should be handled by a single, arbitrarily selected thread within the process.
If you want a dedicated thread in your process to handle some signals, here is an example from pthread_sigmask(3) shows you how to do it:
The program below blocks some signals in the main thread, and then creates a dedicated thread to fetch those signals via sigwait(3). The following shell session demonstrates its use:
$ ./a.out &
[1] 5423
$ kill -QUIT %1
Signal handling thread got signal 3
$ kill -USR1 %1
Signal handling thread got signal 10
$ kill -TERM %1
[1]+ Terminated ./a.out
Program source
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>
/* Simple error handling functions */
#define handle_error_en(en, msg) \
do { errno = en; perror(msg); exit(EXIT_FAILURE); } while (0)
static void *
sig_thread(void *arg)
{
sigset_t *set = arg;
int s, sig;
for (;;) {
s = sigwait(set, &sig);
if (s != 0)
handle_error_en(s, "sigwait");
printf("Signal handling thread got signal %d\n", sig);
}
}
int
main(int argc, char *argv[])
{
pthread_t thread;
sigset_t set;
int s;
/* Block SIGQUIT and SIGUSR1; other threads created by main()
will inherit a copy of the signal mask. */
sigemptyset(&set);
sigaddset(&set, SIGQUIT);
sigaddset(&set, SIGUSR1);
s = pthread_sigmask(SIG_BLOCK, &set, NULL);
if (s != 0)
handle_error_en(s, "pthread_sigmask");
s = pthread_create(&thread, NULL, &sig_thread, (void *) &set);
if (s != 0)
handle_error_en(s, "pthread_create");
/* Main thread carries on to create other threads and/or do
other work */
pause(); /* Dummy pause so we can test program */
}
Read carefully signal(7) & pthread(7) & pthread_kill(3) & sigprocmask(2) & pthread_sigmask(3) -which you could use (to block SIGINT in unwanted threads). Read also a pthread tutorial.
Avoid using signals to communicate or synchronize between threads. Consider e.g. mutexes (pthread_mutex_lock etc...) and condition variables (pthread_cond_wait etc...).
If one of the threads runs an event loop (e.g. around poll(2)...) consider using signalfd(2).

How to block signals in C?

I'm trying to create a program that blocks the signal SIGUSR1 and the it unblocks the signal.
In the middle I want to see that the signal is blocked using sigpending. But it always says that the signal isn't blocked, and I can use the signal when it's supposed to be blocked.
This is the code that I have.
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
static void signals(int signaln)
{
switch (signaln) {
case SIGUSR1:
printf("Signal SIGUSR1\n"); break;
}
return;
}
main()
{
sigset_t set,set2;
struct sigaction sigs;
sigs.sa_handler = signals;
sigemptyset(&sigs.sa_mask);
sigs.sa_flags=SA_ONESHOT;
sigaction(SIGUSR1, &sigs,0);
sigemptyset(&set);
sigemptyset(&set2);
sigaddset(&set,SIGUSR1);
if(sigprocmask(SIG_BLOCK, &set, NULL)==0){
printf("Blocking SISGUSR1...\n");
}
sigpending(&set2);
if (sigismember(&set2,SIGUSR1)==1)
{
printf("The signal is blocked\n"); //it should print this
}
wait(2);
kill(getpid(),SIGUSR1); //the signal shouldn't work
wait(2);
if(sigprocmask(SIG_UNBLOCK, &set, NULL)==0){
printf("Unblocking SIGUSR1\n");
}
}
Could anyone help me?
sigpending doesn't tell you whether a signal is blocked. It tells you whether a signal is waiting to be delivered. (i.e., the signal is blocked and one has been sent.)
Also, blocked doesn't meean that the signal won't be delivered; it means that the signal won't be delivered now. So you can send the signal, and it will be delivered as soon as the signal is unblocked; probably after the call to sigprocmask(SIGUNBLOCKED...) but before the call to printf, so you'll probably see the signal received message before you see the "unblocking" message.

Resources