为什么竞赛条件会循环发生?

时间:2019-05-26 02:59:38

标签: c pthreads race-condition

我有一个模拟串行与并行计算的代码。但是,似乎有比赛条件。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>

void *foo(void *para) {
    printf("This is Thread %d running...\n", *(size_t *)para);
    fflush(stdout);
    sleep(2);
}

int main(void)
{
    /* loop version
    for (size_t i = 0; i < 4; i++) {
        foo((void *)&i);
    }
    */

    pthread_t pool[4];
    for (size_t i = 0; i < 4; i++) {
        pthread_create(&pool[i], NULL, foo, (void *)&i);
    }

    for (size_t i = 0; i < 4; i++) {
        pthread_join(pool[i], NULL);
    }

    return 0;
}

输出:

[william@Notebook Downloads]$ time ./a.out 
This is Thread 1 running...
This is Thread 2 running...
This is Thread 4 running...
This is Thread 3 running...

real    0m2.003s
user    0m0.003s
sys     0m0.000s

[william@Notebook Downloads]$ time ./a.out 
This is Thread 3 running...
This is Thread 3 running...
This is Thread 2 running...
This is Thread 4 running...

real    0m2.003s
user    0m0.003s
sys     0m0.000s

当竞争条件发生时,大多数示例都是在您有多个线程尝试编写共享值的情况下。但是,此代码中根本没有写操作。那么,为什么会这样呢?是因为for循环没有按顺序执行吗?

2 个答案:

答案 0 :(得分:3)

我没有阅读您的问题。我只是看了一下您的代码,观察到发现了一个巨大的问题,这很可能是您所问问题的根本原因。看下面的循环代码:

pthread_t pool[4];
for (size_t i = 1; i <= 4; i++) {
    pthread_create(&pool[i], NULL, foo, (void *)&i);
}

您有一个大小为4的“数组”,但是您正在遍历索引[1..4]。 C和C ++数组从索引0开始,到(len-1)结束。换句话说,您应该遍历索引[0..3]。将任何内容插入pool[4]都会创建未定义的行为。

代替此行:

for (size_t i = 1; i <= 4; i++) {

您想要这个:

for (size_t i = 0; i < 4; i++) {

对执行pthread_join语句的第二个循环应用相同的修复程序。

还将&i用作线程参数还会导致其他未定义的行为。您的线程正在访问一个变量的地址,该变量由主线程不断变化,然后超出范围。

答案 1 :(得分:3)

虽然较早的答案解决了您的代码问题,但这并不是您所要提出的问题的原由。

问题是您要向每个线程传递相同的参数。线程正在打印i当时发生的任何事情,您不断更改的值。线程尝试访问它时,i甚至可能不存在。

您需要传递不同的指针,而不是每次都传递相同的指针(例如,仅为线程分配的指针,或者指向数组的不同元素的指针,这些指针保证不会超出线程的寿命)。另外,由于指针本身是复制的,因此可以将足够小的整数强制转换为指针,然后让线程将指针强制强制转换为整数。