【问题标题】:Why race condition happens in loop? [duplicate]为什么竞争条件发生在循环中? [复制]
【发布时间】:2019-05-26 02:59:37
【问题描述】:

我有一个代码来模拟串行与并行计算。但是,它似乎有一个竞争条件。

#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循环没有按顺序执行?

【问题讨论】:

  • 为什么会发生什么?

标签: c pthreads race-condition


【解决方案1】:

虽然较早的答案解决了您的代码问题,但这并不是您所询问的问题的原因,正如其作者所假设的那样。

问题是您将相同的参数传递给每个线程。线程正在打印任何 i 当时恰好是,你不断变化的值。 i 在线程尝试访问它时甚至可能不存在。

您需要传递不同的指针,而不是每次都传递相同的指针(例如,只为线程分配的东西,或者指向数组中不同元素的指针,这些元素保证比线程更长寿)。或者,由于指针本身被复制,您可以将足够小的整数转换为指针,然后让线程将指针转换回整数。

【讨论】:

  • 谢谢,有什么办法可以解决吗?
  • 这是正确的。对于额外的点,最好指出为什么称其为“竞争条件”为时过早,并演示创建四个值而不是一个更改 4 次的值。
  • @user762750,已添加回答
【解决方案2】:

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

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 语句的第二个循环应用相同的修复。

同时传递&amp;i 作为线程参数会导致额外的未定义行为。您的线程正在访问一个变量的地址,该变量由主线程不断更改,然后超出范围。

【讨论】:

  • 即使我将循环更改为for (size_t i = 0; i &lt; 4; i++) {,它仍然会发生
  • 同时传递&amp;i 作为线程参数会导致额外的未定义行为。您的线程正在访问一个变量的地址,该变量由主线程不断更改,然后超出范围。
  • 谢谢,有什么办法可以解决吗?
  • 是的 - 传递 (void*)i 而不是 &amp;i 并在线程过程中转换回 size_t
猜你喜欢
  • 2012-01-01
  • 1970-01-01
  • 2018-07-24
  • 1970-01-01
  • 1970-01-01
  • 2017-12-29
  • 2021-08-27
  • 1970-01-01
  • 2017-03-24
相关资源
最近更新 更多