线程不能计数,给出错误的结果 [英] Thread can't count, giving wrong result

查看:180
本文介绍了线程不能计数,给出错误的结果的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我写了这段代码

  #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年。你能解释一下为什么会发生这种情况或者背后的原因是什么?如何解决它。您的答案和理由肯定会有很大的帮助。

解决方案

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

(1) 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆