我写了这段代码

#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);
}
并显示此结果。

有时它将cnt设置为2000,但是在大多数情况下它给出的结果小于2000。您能解释一下为什么会发生这种情况,或者是其背后的原因是什么?如何解决。您的回答和原因一定会对您有所帮助。

最佳答案

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

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

~$ 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拳头移至%eax(2)然后在%exc中添加一个
(3)将%eax移回cnt
并且由于在此行之间切换了线程上下文,因此多个线程读取了相同的cnt值。因此cnt++不是原子的。

注意:全局变量与cnt一样是线程可共享的,而您在i中声明的局部变量(如count())则是线程特定的。

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

仅显示修改后的代码
#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
}

这样会很好!一些例子:
nms@NMS:~$ ./thread
OK! cnt=2000
nms@NMS:~$ ./thread
OK! cnt=2000
nms@NMS:~$ ./thread
OK! cnt=2000

关于c - 线程无法计数,给出错误的结果,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/14004993/

10-12 16:09