1
votes

I have written a code where I have created two child threads from the parent thread.

Then, with receiving a signal from another terminal inside those child threads, I printed the threadID and exited the thread.

I have 2 questions.

  1. I'm receiving the signal from the child thread. Why is it printing the threadID of the parent thread?

  2. After killing the parent thread, how can be the child threads alive??

The Code :

void sig_handler(int signo)
{
    if (signo == 1){
        printf("%d\n", pthread_self());
        pthread_exit(NULL);
    }
}

void* doSomeThing(void* arg)
{
    printf("In function -> %d\n", pthread_self());
    if (signal(1, sig_handler) == SIG_ERR)
        printf("\ncan't catch SIGHUP\n");
    while(1)
        sleep(1);
    return NULL;
}

int main(int argc, char *argv[])
{
    printf("In function -> %d\n", pthread_self());
    char *ch1;
    pthread_t tid1, tid2;
    ch1 = "random";
    int ret1, ret2;

    ret1 = pthread_create(&tid1, NULL, &doSomeThing, (void *) ch1 );
    ret2 = pthread_create(&tid2, NULL, &doSomeThing, (void *) ch1 );

    while(1)
        sleep(1);
    return 0;
}

Here is the image of the output given in terminal :

The first 3 lines are the 3 threadIDs. 1st one is the Main threadIDs, then the two secondary threads.

Then the threadIDs printed from the following block of code.

if (signo == 1){
    printf("%d\n", pthread_self());
    pthread_exit(NULL);
}

Why is this happening???

2
signal doesn't really work with threads.Kerrek SB
Does that mean the pthread_self() function is not giving the proper threadID ?? As it is called after receiving the signal ??jbsu32
@JishnuBanerjee pthread_self() will give the thread id of the calling thread. But the real issue is that it's not possible to have per-thread signal handlers; signal handling is process wide. See an example in the linked man page on how to block signals.P.P
The C standard says: "Use of this function [signal] in a multi-threaded program results in undefined behaviour."Kerrek SB

2 Answers

3
votes

Signals are delivered to the process, not to individual threads. So, you can't have a signal handler just for one thread as you are doing here. What you can do is block signals you are interested in using pthread_sigmask() and let a dedicated thread handle signals using sigwait(), which is the most common way.

0
votes

In addition, you can only safely call async-signal-safe functions from within a signal handler. From the Linux signal man page:

Async-signal-safe functions

A signal handler function must be very careful, since processing elsewhere may be interrupted at some arbitrary point in the execution of the program. POSIX has the concept of "safe function". If a signal interrupts the execution of an unsafe function, and handler either calls an unsafe function or handler terminates via a call to longjmp() or siglongjmp() and the program subsequently calls an unsafe function, then the behavior of the program is undefined.

The linked man page has a list of functions that are safe to call from within a signal handler. If the function is not on that list, it is unsafe to call it. No exceptions.

Note that neither printf() nor pthread_exit() are on the list of async-signal-safe functions.

And calling pthread_exit() from within a signal handler creates several other problems:

  • The thread that exits is generally not under any control. In many cases, the signal can be delivered to any thread.

  • The exiting thread can leave objects in an unknown state - a mutex can be left locked by a thread that no longer exists, for example.

  • Any thread cleanup handlers registered with pthread_cleanup_push() will also be called from within a signal handler context.