次の例を考えてみましょう。目標は、値を「計算」するスレッドと、計算された値を消費して使用するスレッドの 2 つのスレッドを使用することです (これを単純化しようとしました)。計算スレッドは、条件変数を使用して値が計算され、準備ができていることを他のスレッドに通知します。その後、待機中のスレッドが値を消費します。
// Hopefully this is free from errors, if not, please point them out so I can fix
// them and we can focus on the main question
#include <pthread.h>
#include <stdio.h>
// The data passed to each thread. These could just be global variables.
typedef struct ThreadData
{
pthread_mutex_t mutex;
pthread_cond_t cond;
int spaceHit;
} ThreadData;
// The "computing" thread... just asks you to press space and checks if you did or not
void* getValue(void* td)
{
ThreadData* data = td;
pthread_mutex_lock(&data->mutex);
printf("Please hit space and press enter\n");
data->spaceHit = getchar() == ' ';
pthread_cond_signal(&data->cond);
pthread_mutex_unlock(&data->mutex);
return NULL;
}
// The "consuming" thread... waits for the value to be set and then uses it
void* watchValue(void* td)
{
ThreadData* data = td;
pthread_mutex_lock(&data->mutex);
if (!data->spaceHit)
pthread_cond_wait(&data->cond, &data->mutex);
pthread_mutex_unlock(&data->mutex);
if (data->spaceHit)
printf("You hit space!\n");
else
printf("You did NOT hit space!\n");
return NULL;
}
int main()
{
// Boring main function. Just initializes things and starts the two threads.
pthread_t threads[2];
pthread_attr_t attr;
ThreadData data;
data.spaceHit = 0;
pthread_mutex_init(&data.mutex, NULL);
pthread_cond_init(&data.cond, NULL);
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
pthread_create(&threads[0], &attr, watchValue, &data);
pthread_create(&threads[1], &attr, getValue, &data);
pthread_join(threads[0], NULL);
pthread_join(threads[1], NULL);
pthread_attr_destroy(&attr);
pthread_mutex_destroy(&data.mutex);
pthread_cond_destroy(&data.cond);
return 0;
}
私の主な質問は、コンパイラによって行われる潜在的な最適化に関係しています。コンパイラは、トリッキーな最適化を実行して、次のようなプログラム フローを「最適化」することを許可されていますか?
void* watchValue(void* td)
{
ThreadData* data = td;
pthread_mutex_lock(&data->mutex);
if (!data->spaceHit) // Here, it might remember the result of data->spaceHit
pthread_cond_wait(&data->cond, &data->mutex);
pthread_mutex_unlock(&data->mutex);
if (remember the old result of data->spaceHit without re-getting it)
printf("You hit space!\n");
else
printf("You did NOT hit space!\n");
// The above if statement now may not execute correctly because it didn't
// re-get the value of data->spaceHit, but "remembered" the old result
// from the if statement a few lines above
return NULL;
}
私は、コンパイラの静的分析がdata->spaceHit
2 つのステートメント間で変化しないと判断し、新しい値を再取得する代わりにif
古い値を使用することを正当化する可能性があることに少し偏執的です。data->spaceHit
このコードが安全かどうかを知るには、スレッド化とコンパイラの最適化について十分に知りません。それは...ですか?
注: これは C で記述し、C および C++ としてタグ付けしました。これを C++ ライブラリで使用していますが、C スレッド API (pthreads および Win32 スレッド) を使用しており、C++ ライブラリのこの部分に C を埋め込むオプションがあるため、これを C と C++ の両方としてタグ付けしました。 .