共有状態にアクセスしているときにミューテックスを保持しているコードがあるとします。ある時点で、新しいスレッドを作成する必要があると判断し、ミューテックスを保持したまま pthread_create を呼び出します。これは安全と考えられますか?
共有状態が、正常に作成された pthread の数を追跡するグローバル カウンターであり、別のスレッドがこのカウンターを使用して情報を画面にライブで表示するとします。さらに、pthreads の数が特定の最大値 (明確にするために 10 とします) よりも大きくならないようにします。
カウンターが現在 9 であるとします。カウンターをインクリメントしてから、pthread_create を呼び出す前にミューテックスを解放すると、pthread_create が失敗する可能性があり、実際に正常に作成されたよりも多くのスレッド (10) がカウンターに誤って表示されます ( 9)。
一方、最初にミューテックスを解放し、次に pthread_create を呼び出し、呼び出しが成功した場合にカウンターをインクリメントするためにミューテックスを再取得した場合、ミューテックスを解放してから pthread_create から戻るまでの間に、別のスレッドが pthread_create を呼び出した可能性もあります。カウンターをインクリメントしました(10に)。したがって、11 番目の pthread を作成したことになり、カウンターは 11 になります。
したがって、共有状態の一貫性を保証する唯一の方法は、pthread_create を呼び出している間にミューテックスを保持することです。しかし、一般に、ミューテックスを保持している間に未知のコードを呼び出すべきではないことを認識しているため、そのような場合に何ができるかわかりません。
編集:これは、この問題が発生するサンプルコードです
#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;
}