Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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);
}
like image 267
June Avatar asked Oct 30 '17 16:10

June


People also ask

How do you terminate a thread in C?

C Thread Termination Example The threads exit from the start function using the pthread_exit() function with a return value. In the main function after the threads are created, the pthread_join() functions are called to wait for the two threads to complete.

Does exit terminate all threads?

Calling the exit subroutine terminates the entire process, including all its threads. In a multithreaded program, the exit subroutine should only be used when the entire process needs to be terminated; for example, in the case of an unrecoverable error.

What happens to thread when process exits?

Exiting the main thread will not result in the process exiting if there are any other threads still active. According to the old-fashioned model of how processes exit, a process was in control of all its threads and could mediate the shutdown of those threads, thereby controlling the shutdown of the process.

How do I cancel my Pthread?

The pthread_exit() function terminates the calling thread, making its exit status available to any waiting threads. Normally, a thread terminates by returning from the start routine that was specified in the pthread_create() call which started it.


1 Answers

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.

like image 150
WLGfx Avatar answered Nov 06 '22 23:11

WLGfx