考虑以下示例。目标是使用两个线程,一个用于“计算”一个值,一个用于消耗和使用计算值(我试图简化这一点)。计算线程通过使用条件变量向另一个线程发出信号,表明该值已计算并准备就绪,之后等待线程使用该值。
// 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
两个语句之间没有变化if
,因此证明使用旧值data->spaceHit
而不是重新获取新值是合理的。我对线程和编译器优化知之甚少,无法知道这段代码是否安全。是吗?
注意:我是用 C 语言编写的,并将其标记为 C 和 C++。我在 C++ 库中使用它,但由于我使用 C 线程 API(pthreads 和 Win32 线程)并且可以选择将 C 嵌入到 C++ 库的这一部分中,因此我将其标记为 C 和 C++ .