线程无法计数,给出错误的结果

我写了这段代码

#include  /* Input/Output */ #include  /* General Utilities */ #include  /* POSIX Threads */ unsigned int cnt=0; /*Count variable%*/ const int NITERS=1000; void count() { int i=0; for(i=0; i<NITERS; i++) { cnt++; } pthread_exit(0); } int main() { pthread_t tid1,tid2; /* create threads 1 and 2 */ pthread_create(&tid1,NULL,count,NULL); pthread_create(&tid2,NULL,count,NULL); /* Main block now waits for both threads to terminate, before it exits If main block exits, both threads exit, even if the threads have not finished their work */ pthread_join(tid1,NULL); pthread_join(tid2,NULL); if(cnt!=(unsigned)NITERS*2) { printf("BOOM! cnt=%d, it should be %d\n",cnt,NITERS*2); } else { printf("OK! cnt=%d\n",cnt); } exit(0); } 

它展示了这个结果。 结果代码

有一段时间它得到cnt为2000但是大部分时间它的结果都不到2000.你能解释它为什么会发生这种情况或者背后的原因是什么? 如何解决它。 你的答案和理由肯定会有很大的帮助。

unsigned int cnt=0; 在线程和操作之间是可共享的++不是primefaces地增加cnt 。 两个线程可以读取相同的cnt值并增加,并覆盖cnt 。 您需要应用一些并发控制机制,如信号量或互斥量。


如果你要使用以下命令反汇编代码(假设代码名是thread1.c

 ~$ gcc thread.c -lpthread -S 

输出程序集代码名称是thread1.s

你的wil发现cnt++在你的代码中是低级别的一条指令:

  movl $0, -12(%ebp) jmp .L2 .L3: movl cnt, %eax addl $1, %eax movl %eax, cnt addl $1, -12(%ebp) .L2: movl NITERS, %eax 

(1) cnt拳头移动到%eax
(2)然后加一个%exc
(3)将%eax移回cnt

并且由于此行之间的线程上下文切换, cnt相同值由多个线程读取。 因此cnt++不是primefaces的。

注意:全局变量是可共享的线程,如cnt ,并且您在count()声明的局部变量(如i count()是特定于线程的。


我修改了你的代码并使用信号量强加了并发控制,现在它可以正常工作。

仅显示修改后的代码

 #include  /* POSIX Threads */ #include  unsigned int cnt=0; /*Count variable%*/ const int NITERS=1000; sem_t mysem; void count() { int i=0; for(i=0; i 

这样做会很好! 一些例子:

 nms@NMS:~$ ./thread OK! cnt=2000 nms@NMS:~$ ./thread OK! cnt=2000 nms@NMS:~$ ./thread OK! cnt=2000 

您的2个线程无需保护即可访问共享资源,因此适用竞争条件。 增加操作不是primefaces操作,所以你可以在机器操作方面实际上有这样的东西:

 Thread 1 Thread 2 Load value of cnt Load value of cnt Increase value of cnt Write value of cnt Increase value of cnt Write value of cnt 

请注意,虽然两个线程都增加了cnt ,但实际上只增加了1.如果您希望结果是确定性的,则需要保护共享资源( cnt ),例如通过在访问之前锁定它。

你有一个竞争条件问题。更多信息(我知道它谈论视觉基础,只是跳过这些事情) 在这里 。
要解决它,您需要一个互斥锁,将其声明为全局变量:

 pthread_mutex_t mux; 

初始化它:

 pthread_mutex_init(&mux,NULL); 

然后用它来读取共享变量:

 void count() { int i=0; for(i=0; i 

所有这一切都是因为有两个线程递增相同的变量,它们在递增变量之前获取变量并将它们放入寄存器中。因此,它们认为它们读取的值并不唯一:每个线程都有自己的副本,因此每个线程都可以忽略另一方的变化,直到它们有效地将其写入内存中的地址。
注意 :如果你想让线程以有序的方式更新变量(即:线程1计数到NITERS而不被中断,当线程2开始计数时),你必须在for之前锁定互斥锁。

增量运算符通常由读 – 修改 – 写实现,它是非primefaces的。

跨线程的非primefaces读取 – 修改 – 写入有时可以执行此操作:

 Thread 1: Thread 2: count Read count ... 1 Add 1 Read count 1 Write count Add 1 2 ... Write count 2 

导致计数低于预期。

如果要跨多个线程访问共享资源,则需要使用某种线程感知锁定机制(如互斥锁)来保护它。