Reputation: 45
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!
Upvotes: 1
Views: 1837
Reputation: 58741
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.
Upvotes: 1