简体   繁体   中英

Is it safe to call pthread_create while holding a mutex?

Suppose I have code that is holding a mutex while accessing some shared state. At some point, I determine I need to create a new thread, and thus call pthread_create, while still holding the mutex. Is this considered safe?

Suppose my shared state is a global counter that keeps track of the number of successfully created pthreads, and another thread uses this counter to display the information live on the screen. Additionally I do not want the number of pthreads to become larger than a certain maximum value (say 10 for definiteness).

Let's say the counter is currently at 9. If I increment the counter and then release the mutex before calling pthread_create, there is a possibility that pthread_create might fail, and then the counter is erroneously showing more threads (10) than I actually created successfully (9).

On the other hand if I first release the mutex, then call pthread_create, and then reacquire the mutex to increment the counter if the call was successful, then in the meantime between releasing the mutex and returning from pthread_create, another thread could have also called pthread_create and incremented the counter (to 10). Thus I will have then created an 11th pthread and the counter becomes 11. But I was supposed not to have more than 10 pthreads created.

So it seems like the only way to guarantee consistency in the shared state is to hold the mutex while calling pthread_create. But I am aware that in general, one should not be calling unknown code while holding a mutex, so I don't know what can be done in such a case.

EDIT: Here is some sample code that would have this issue

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

void *do_stuff(void *arg);

int pthreads_counter = 0;
pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;

#define MAX_PTHREADS_COUNT 10

/* Could potentially be called from multiple threads simultaneously */
int create_thread_and_increment_counter()
{
    pthread_t thread;

    if (pthread_mutex_lock(&mtx) != 0)
        return -1;

    if (pthreads_counter >= MAX_PTHREADS_COUNT) {
        pthread_mutex_unlock(&mtx);
        return -1;
    }

    ++pthreads_counter;

    if (pthread_create(&thread, NULL, do_stuff, NULL) != 0) {
        --pthreads_counter;
        pthread_mutex_unlock(&mtx);
        return -1;
    }

    pthread_mutex_unlock(&mtx);
    return 0;
}

void *do_stuff(void *arg)
{
    /* do stuff */
    return NULL;
}

/* Created somewhere else */
void *display_thread(void *arg)
{
    while (1) {
        if (pthread_mutex_lock(&mtx) != 0)
            break;

        printf("%d\n", pthreads_counter);
        pthread_mutex_unlock(&mtx);
        usleep(1000000);
    }

    return NULL;
}

保持互斥时调用pthread_create()很好。

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM