June
June

Reputation: 139

How to send cancelation request from main() to thread?

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

Answers (1)

WLGfx
WLGfx

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

Related Questions