Signal handling among pthreads
Asked Answered
U

1

6

I am trying to learn signal handling among processes and threads. The answer to a few questions would help me understand it better.

I know that a process can send a signal to the process group and allow multiple processes to receive the same signal, but I am not sure about threads.

  • Can signals sent to all pthreads be handled by more than one pthread at the same time?

I setup my program to block all signals using pthread_sigmask(), I have two threads use sigwait(SIGUSR1) to wait for signals, and I have the main thread send SIGUSR1 signals. It seems that everything works well when only one thread is handling the signals (I comment out the code in the other), but when both are running the sigwait() code it hangs or terminates too quickly.

The code is pasted below.

sig_atomic_t signals = 0;
sig_atomic_t sigusr1_signals = 0;
sig_atomic_t sigusr2_signals = 0;
sig_atomic_t count = 0;
sig_atomic_t totalcount = 0;

sigset_t globalset;

int WAIT = 1;           /* false = 0, true = 1 */

static int SIGNALS_SENT = 0;
static int SIGNALS_RECEIVED = 0;

void *sig1handler1(void *argv);

void *reporterhandler(void *argv);

int random_number(int min, int max);

int main(void) {

    pthread_t threads[2];   /* create an array to store a number of threads */

    //int *p_status = &status;
    sigfillset(&globalset);
    pthread_sigmask(SIG_BLOCK, &globalset, NULL);

    /* Generate signal handling threads */
    if (pthread_create(&threads[0], NULL, &sig1handler1, NULL) > 0)
    {
        printf("Thread creation failure!\n");
        return -1;
    }


    /* create reporting thread */
    if (pthread_create(&threads[1], NULL, &reporterhandler, NULL) > 0)
    {
        printf("Thread creation failure!\n");
        return -1;
    }

    /* Signal all threads to begin work concurrently */
    WAIT = 0;

    int c = 0;
    while(c < 100)
    {
        int value = random_number(1, 2);
        if (value == 1)
            kill(0, SIGUSR1);
        else
            kill(0, SIGUSR2);

        SIGNALS_SENT++;
        c++;
        usleep(10000);
    }

    kill(0, SIGINT);


    /* Wait for each thread to finish and join */
    int i = 0;
    for(i = 0; i < 2; i++)
    {
        if (pthread_join(threads[i], NULL) > 0)
        {
            printf("Thread [%u] join failure!\n", (unsigned int)threads[i]);
            return -1;
        }

        printf("THREAD [%u] returned.\n", (unsigned int)threads[i]);
    }

    printf("Parent Process [%d] exiting successfully.\n", getpid());
    return EXIT_SUCCESS;
}


void *sig1handler1(void *argv)
{
    pthread_t tid = pthread_self();
    printf("THREAD[%u] sig1handler1: waiting for signal to do some work...\n", (unsigned int)tid);

//  sigset_t myset;
//  sigfillset(&myset);
//  sigdelset(&myset, SIGINT);
//  sigdelset(&myset, SIGUSR1);
//  pthread_sigmask(SIG_SETMASK, &myset, NULL);

    /* Wait for a signal to start work */
    while (WAIT);

    int sig;
    int count = 0;

    while(1)
    {
        sigwait(&globalset, &sig);
        if (sig == SIGUSR1)
        {
            sigusr1_signals++;
            signals++;
            count++;
            //printf("thread1: caught SIGUSR1 signal!\n");
        }
        else if (sig == SIGINT)
        {
            printf("thread1: caught SIGINT signal, detected SIGUSR1 %d times, and terminating!\n", count);          pthread_exit(NULL);
        }
    }

    //printf("THREAD[%u] sig1handler1: doing some work!\n", (unsigned int)tid);
    //return (void *)EXIT_SUCCESS;
    //return (void *)NULL;
    pthread_exit(NULL);
}

void *reporterhandler(void *argv)
{
    pthread_t tid = pthread_self();
    printf("THREAD[%u] reporter: waiting for signal to do some work...\n", (unsigned int)tid);

    int sig;
    int count = 0;

//  sigset_t myset;
//  sigfillset(&myset);
//  sigdelset(&myset, SIGINT);
//  sigdelset(&myset, SIGUSR1);
//  sigdelset(&myset, SIGUSR2);
//  pthread_sigmask(SIG_SETMASK, &myset, NULL);

    /* Wait for a signal to start work */
    while (WAIT);

    while(1)
    {
        sigwait(&globalset, &sig);
        if (sig == SIGUSR1)
        {
            sigusr1_signals++;
            signals++;
            count++;
            totalcount++;
            SIGNALS_RECEIVED++;
        }
        else if (sig == SIGUSR2)
        {
            sigusr2_signals++;
            signals++;
            count++;
            totalcount++;
            SIGNALS_RECEIVED++;
        }
        else if (sig == SIGINT)
        {
            printf("Reporter: SIGUSR1 detected %d times\n", sigusr1_signals);
            printf("Reporter: SIGUSR2 detected %d times\n", sigusr2_signals);
            printf("Reporter: detected %d signals\n", totalcount);
            printf("Reporter: SIGNALS_SENT %d \n", SIGNALS_SENT);
            printf("Reporter: SIGNALS_REC %d \n", SIGNALS_RECEIVED);
            pthread_exit(NULL);
        }

        /* Display Report after detecting 10 signals */
        if (count == 10)
                    sigusr1_signals, sigusr2_signals);

            count = 0;
        }
    }

    //printf("THREAD[%u] reporter: doing some work!\n", (unsigned int)tid);
    pthread_exit(NULL);
}

int random_number(int min, int max)
{
    if (min < max)
    {
        max = max + 1;      /* include the max value */
        return (rand() % (max - min)) + min;
    }

    return -1;
}   
Unmerciful answered 5/10, 2014 at 0:19 Comment(4)
I believe the mantra is 'signals are sent to process' and will be delivered once to a thread that is not ignoring the signal.Hepzi
I am relatively sure that signals can be sent to a specific thread or all threads. I don't know if only one can handle it, but I think they all can receive the signal.Unmerciful
@0d0a signal handlers aren't relevant when you block the signals and then poll for them.Lawrencelawrencium
Hi o11c, thanks for the info. I am aware that you use one or the other. My code uses the names sighandler for functions, but they really are the work done by the thread, which sits and waits for signals.Unmerciful
S
4
  • Can signals [be] sent to all pthreads [and] be handled by more than one pthread at the same time?

Not at the same time. These are the possibilities:

  1. Send a signal to a process (kill()): In this case, any thread listening for the signal can receive it, but just one will do it.
  2. Send a signal to a process group: The signal will be delivered to all processes in the group.
  3. Send a signal to a specific thread (pthread_kill()): now you are sending it to a specific thread ID.

Prototype:

int pthread_kill(pthread_t thread, int sig);

In your case, I think the only way to deliver the signal to all threads is iterating along all your thread ids to send the signal with pthread_kill().

Spectroradiometer answered 5/10, 2014 at 1:20 Comment(1)
This is what I needed to find out. Thank you! I ran some experiments and found out the same thing, but I wasn't sure because I am not certain when it comes to my code. This explains it.Unmerciful

© 2022 - 2024 — McMap. All rights reserved.