线程不能计数,给出错误的结果 [英] Thread can't count, giving wrong result
问题描述
我写了这段代码
#include< stdio.h> / *输入/输出* /
#include< stdlib.h> / *常规工具* /
#include< pthread.h> / * POSIX线程* /
unsigned int cnt = 0; / *计数变量%* /
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;
/ *创建线程1和2 * /
pthread_create(& tid1,NULL,count,NULL);
pthread_create(& tid2,NULL,count,NULL);
/ *主程序现在等待两个线程终止,然后退出
如果主程序段退出,两个线程退出,即使线程没有完成
的工作* /
pthread_join(tid1,NULL);
pthread_join(tid2,NULL);
if(cnt!=(unsigned)NITERS * 2)
{
printf(BOOM!cnt =%d,应该是%d \ n,cnt,NITERS * 2 );
}
else
{
printf(OK!cnt =%d\\\
,cnt);
}
exit(0);
}
,并显示此结果。
一些时间到了2000年,但大多数时候它的结果都低于2000年。你能解释一下为什么会发生这种情况或者背后的原因是什么?如何解决它。您的答案和理由肯定会有很大的帮助。
如果您使用以下命令反汇编代码(假设代码名称 输出汇编代码名称是 您的代码中发现 (1) 此行之间的线程上下文切换,相同的值 unsigned int cnt = 0; code>在线程中可共享,并且操作
是线程特定的。 ++
不是原子地增加 cnt
。两个线程可以读取 cnt
的相同值并增加并覆盖 cnt
。您需要应用一些像信号量或互斥体这样的并发控制机制。
thread1.c code $)
$ b $ $ p $ code $〜$ gcc thread.c -lpthread -S
thread1.s
。
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
cnt
fist移至%eax
(2)然后添加一个到%exc
(3)将%eax
移动到 cnt
返回
cnt
被多个线程读取。因此 cnt ++
不是原子的。注意:全局变量是线程可共享的,如 cnt
,局部变量如您在 count()
中声明的code> i
我修改了代码并使用信号量强加并发控制,现在它可以正常工作。
仅显示已修改的代码
#include< pthread.h> / * POSIX线程* /
#include< semaphore.h>
unsigned int cnt = 0; / *计数变量%* /
const int NITERS = 1000;
sem_t mysem;
void count()
{
int i = 0;
for(i = 0; i< NITERS; i ++)
{
sem_wait(& mysem);
cnt ++;
sem_post(& mysem);
}
pthread_exit(0);
int main()
{
if(sem_init(& mysem,0,1)){
perror(init);
}
//其余的代码
}
将工作良好!一些例子:
nms @ NMS:〜$ ./thread
OK! cnt = 2000
nms @ NMS:〜$ ./thread
OK! cnt = 2000
nms @ NMS:〜$ ./thread
OK! cnt = 2000
I wrote this piece of code
#include <stdio.h> /* Input/Output */
#include <stdlib.h> /* General Utilities */
#include <pthread.h> /* 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);
}
and it exhibits this result.
Some time it get cnt to be 2000 but most of the time it is giving the result less than 2000. Can you please explain why is it happening or what is the reason behind this? How to fix it. Your answers and reasons will be sure of great help.
unsigned int cnt=0;
is share-able among the threads and operation ++
is not atomically increase cnt
. Two thread may read same values of cnt
and increase, and overwrites cnt
. You need to apply some concurrency control mechanism like semaphore, or mutex.
If you would disassemble code using following command (suppose code name is thread1.c
)
~$ gcc thread.c -lpthread -S
The output assembly code name is thread1.s
.
your wil find cnt++
is more then one instruction in low level in your code:
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
fist move to %eax
(2) then add one to %exc
(3) move %eax
into cnt
back
And due to thread context switching in between this line, same value of cnt
is read by more than one threads. hence cnt++
is not atomic.
Note: Global variable are thread shareable like cnt
, and local variable like i
that you declared in count()
is thread specific.
I modified your code and imposed concurrency control using semaphore, now it would work fine.
Only modified code shown
#include <pthread.h> /* POSIX Threads */
#include <semaphore.h>
unsigned int cnt=0; /*Count variable%*/
const int NITERS=1000;
sem_t mysem;
void count()
{
int i=0;
for(i=0; i<NITERS; i++)
{
sem_wait(&mysem);
cnt++;
sem_post(&mysem);
}
pthread_exit(0);
}
int main()
{
if ( sem_init(&mysem,0,1) ) {
perror("init");
}
// rest of your code
}
This will work good! some examples:
nms@NMS:~$ ./thread
OK! cnt=2000
nms@NMS:~$ ./thread
OK! cnt=2000
nms@NMS:~$ ./thread
OK! cnt=2000
这篇关于线程不能计数,给出错误的结果的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!