我的代码执行以下操作:创建N个线程,每个线程将全局变量计数器增加M次。我使用互斥锁以确保计数器的最终值是M * N.
我想观察没有互斥的情况,为计数器获取不同的值,以便正确评估互斥锁的工作。我注释掉了互斥锁,但结果是一样的。我应该让他们在一段时间内睡觉吗?我该怎么办?
#include <stdio.h>
#include <pthread.h>
#define N 10
#define M 4
pthread_mutex_t mutex;
int counter=0;
void *thread_routine(void *parameter)
{
pthread_mutex_lock(&mutex);
int i;
for (i=0; i<M; i++)
counter++;
pthread_mutex_unlock(&mutex);
}
int main(void)
{
pthread_t v[N];
int i;
pthread_mutex_init(&mutex,NULL);
for (i=0; i<N; i++)
{
pthread_create(&v[i],NULL,thread_routine,NULL);
}
for (i=0; i<N; i++)
{
pthread_join(v[i],NULL);
}
printf("%d %d\n",counter,N*M);
if (N*M==counter)
printf("Success!\n");
pthread_mutex_destroy(&mutex);
return 0;
}
答案 0 :(得分:4)
我不知道你使用了什么编译器,但在这种情况下g ++会完全消除线程并在编译时计算计数器的最终值。 为了防止这种优化,你可以使计数器变量不稳定
volatile int counter=0;
由于这将告诉编译器变量可以随时由外部资源更改,因此不得对可能有副作用的变量进行任何优化。由于外部资源可能会更改该值,因此最终值可能不是N * M的结果,因此计数器的值将在运行时计算。 WhozCraig在他的评论中所说的内容也很可能适用于您的案例。但我认为他的意思是M,而不是N.
除了你原来的问题:当你连接所有线程时读取计数器,可能值得为每个线程提供自己的计数器,并在完成计算时对所有线程的计数器求和。这样,您可以在没有任何锁定或原子操作的情况下计算最终值。
编辑:
您使用互斥锁的第一次测试看起来像这样
#define N 10
#define M 10000000
pthread_mutex_t mutex;
volatile int counter=0;
void *thread_routine(void *parameter)
{
pthread_mutex_lock(&mutex);
int i;
for (i=0; i<M; i++)
counter++;
pthread_mutex_unlock(&mutex);
}
和你没有互斥的第二次测试
#define N 10
#define M 10000000
pthread_mutex_t mutex;
volatile int counter=0;
void *thread_routine(void *parameter)
{
// pthread_mutex_lock(&mutex);
int i;
for (i=0; i<M; i++)
counter++;
// pthread_mutex_unlock(&mutex);
}
而第二次测试在递增计数器变量时将具有预期的竞争条件。
编译可以使用gcc -O3 -lpthread test.c
完成