Reputation: 139
I need to block Ctrl+C
signal(SIGINT
) in thread_B and main() should handle SIGINT
signal, So whenever user presses Ctrl+C
main() should try to cancel thread_B but thread_B needs to ignore any cancelation request for first 100 seconds and any cancelation request should be honored after 100 seconds and after thread_B terminates main() should terminate, So far Im able to block signal in thread_B but not able to send cancellation request to thread_B from main(), how do I solve this?
Edit:
when thread is running in while loop SIGINT
is disabled, it will not honer any Ctrl+C
request, so it will be in loop forever, how will main()
interrupts the while loop so that it can send cancellation request to thread? any views on this?
Code:
#include <pthread.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <math.h>
#define handle_error_en(en, msg) \
do { errno = en; perror(msg); exit(EXIT_FAILURE); } while (0)
static volatile sig_atomic_t doneflag = 0;
/* ARGSUSED */
static void setdoneflag(int signo) {
doneflag = 1;
}
static void *
thread_func(void *ignored_argument)
{
int s;
sigset_t sigset;
sigemptyset(&sigset);
sigaddset(&sigset, SIGINT);
sigprocmask(SIG_BLOCK, &sigset, NULL);
while (!doneflag)
{
sleep(1);
printf("Hello\n");
s = pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
if (s != 0)
handle_error_en(s, "pthread_setcancelstate");
printf("thread_func(): started; cancellation disabled\n");
sleep(5);
printf("thread_func(): about to enable cancellation\n");
s = pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
if (s != 0)
handle_error_en(s, "pthread_setcancelstate");
/* sleep() is a cancellation point */
sleep(10); /* Should get canceled while we sleep */
// /* Should never get here */
// printf("thread_func(): not canceled!\n");
}
return NULL;
}
int
main(void)
{
pthread_t thr;
void *res;
int s;
sigset_t sigset;
int recvdSig;
sigwait(&sigset,&recvdSig);
s = pthread_create(&thr, NULL, &thread_func, NULL);
if (s != 0)
handle_error_en(s, "pthread_create");
//sleep(2); /* Give thread a chance to get started */
if( recvdSig == SIGINT )
{
printf("main(): sending cancellation request\n");
s = pthread_cancel(thr);
if (s != 0)
handle_error_en(s, "pthread_cancel");
}
struct sigaction act;
act.sa_handler = setdoneflag; /* set up signal handler */
act.sa_flags = 0;
if ((sigemptyset(&act.sa_mask) == -1) || (sigaction(SIGINT, &act, NULL) == -1))
{
perror("Failed to set SIGINT handler");
return 1;
}
/* Join with thread to see what its exit status was */
s = pthread_join(thr, &res);
if (s != 0)
handle_error_en(s, "pthread_join");
if (res == PTHREAD_CANCELED)
printf("main(): Terminated\n");
else
printf("main(): thread wasn't canceled (shouldn't happen!)\n");
exit(EXIT_SUCCESS);
}
Upvotes: 6
Views: 651
Reputation: 1179
You don't send the cancel from main() to a pthread. The signal handler will do that. main() will continue until it recieves the same notification from the signal handler.
See below...
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <pthread.h>
#include <stdbool.h>
static bool shutdown;
static bool thread_finished;
pthread_t thread;
void *thread_func(void *ptr) {
while (!shutdown) {
int countdown = 5;
while (!shutdown && countdown--) {
usleep(250 * 1000);
}
printf("Still waiting...\n");
}
printf("Shutdown signal flag set. Closing.");
thread_finished = true;
return 0;
}
void sigint_handler(int sig) {
if (sig == SIGINT) { // handle shutdown
// If you need to bypass then do it here
printf("Sending shutdown signal to thread\n");
shutdown = true;
pthread_join(thread, NULL);
}
}
int main()
{
signal(SIGINT, sigint_handler);
printf("Starting background thread!\n");
shutdown = false;
thread_finished = false;
pthread_create(&thread, NULL, &thread_func, (void*)0);
while (!shutdown && !thread_finished) {
usleep(1500 * 1000);
printf("Still running from main\n");
}
return 0;
}
You can use this same mechanism to shutdown multiple threads before your application finally quits itself.
Upvotes: 1