1
votes

I'm trying to write safe SIGINT handling for my multithreaded application and I'm using sleep() function to simulate entering "unsafe" zone - a place where a thread shouldn't be cancelled. Here's my code:

Global variables:

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>

pthread_mutex_t *global_mutex;
pthread_mutex_t **thread_mutexes;
pthread_mutex_t *firm_mutex;
pthread_attr_t *attr;

Thread:

void *thread(void *data)
{
    int local_tid = *(int *) data; 
    printf("Starting thread %d\n", local_tid);
    for (;;) {
        pthread_mutex_lock(thread_mutexes[local_tid]);
        int scnds = rand() % 5 + 1;
        printf("%d locked\nSleeping for: %d seconds\n", local_tid, scnds);
        sleep(scnds);
        printf("%d woken up!\n", local_tid);
        pthread_mutex_unlock(thread_mutexes[local_tid]);
    }
}

Thread creation:

int main()
{
    int n;
    scanf("%d", &n);
    printf("Starting signal handler with %d threads...\n",n);
    global_mutex = malloc(sizeof(pthread_mutex_t));
    firm_mutex = malloc(sizeof(pthread_mutex_t));
    thread_mutexes = malloc(n * sizeof(pthread_mutex_t *));
    for (int i = 0; i < n; i++) {
        thread_mutexes[i] = malloc(sizeof(pthread_mutex_t));
    }
    attr = malloc(sizeof(pthread_attr_t));
    if (pthread_attr_init(attr) != 0 ) {
        perror("attrinit\n");
        exit(1);
    }
    if (pthread_attr_setdetachstate (attr,PTHREAD_CREATE_JOINABLE) != 0) {
        perror("setdetach\n");
        exit(1);
    }
    for (int i = 0; i < n; i++) {
        pthread_t tid;
        if (pthread_mutex_init (thread_mutexes[i], 0) != 0) {
            perror("mutexinit\n");
            exit(1);
        }
        int *tdata = malloc(sizeof(int));
        *tdata = i;
        if (pthread_create (&tid, attr, watek, tdata) != 0) {
            perror("pthread_create");
            exit(1);
        }
        if (pthread_join (tid, 0) != 0) {
            perror("join\n");
            exit(1);
        }

    }
    return 0;
}

So you would think that after launching with 10 threads, first thread should go to sleep immedietely and in the meantime another should start execution. Unfortuntely, after launching the program with 10 threads I get an output like this:

Starting signal handler with 10 threads...
Starting thread 0
0 locked
sleeping for: 4 seconds
0 woken up!
0 locked
sleeping for: 2 seconds
0 woken up!
0 locked
sleeping for: 3 seconds
0 woken up!
0 locked
sleeping for: 1 seconds
0 woken up!
0 locked
sleeping for: 4 seconds
0 woken up!
0 locked

Basically thread 0 steals all the time! Why aren't other threads executed when 0 sleeps?

1

1 Answers

4
votes
    if (pthread_create (&tid, attr, watek, tdata) != 0) {
        perror("pthread_create");
        exit(1);
    }
    if (pthread_join (tid, 0) != 0) {
        perror("join\n");
        exit(1);
    }

You're creating the first thread and then waiting to pthread_join with it before creating the next one. The next loop iteration, therefore, (creating the next thread) won't happen until the first thread terminates.

If you want all the threads to start right away, just create and start them in the first loop - deal with waiting for them to complete later.