【问题标题】:GCC optimization effect on thread concurrencyGCC对线程并发的优化效果
【发布时间】:2017-09-21 14:41:00
【问题描述】:

我只是在摆弄线程并观察在修改未受保护的全局变量时如何发生竞争条件。具有 3 个线程的简单程序,在具有 100000 次迭代的紧密循环中递增全局变量 -

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

static int global;
pthread_mutex_t lock;

#define LOCK() pthread_mutex_lock(&lock)
#define UNLOCK() pthread_mutex_unlock(&lock)

void *func(void *arg)
{
    int i;

    //LOCK();
    for(i = 0; i < 100000; i++)
    {
        global++;
    }
    //UNLOCK();
}

int main()
{
    pthread_t tid[3];
    int i;

    pthread_mutex_init(&lock, NULL);

    for(i = 0; i < 3; i++)
    {
        pthread_create(&tid[i], NULL, func, NULL);
    }

    for(i = 0; i < 3; i++)
    {
        pthread_join(tid[i], NULL);
    }

    pthread_mutex_destroy(&lock);

    printf("Global value: %d\n", global);
    return 0;
}

当我用 -g 标志编译它并运行对象 5 次时,我得到这个输出:

Global value: 300000
Global value: 201567
Global value: 179584
Global value: 105194
Global value: 205161

这是预期的。经典同步问题在这里。没什么可看的。 但是当我使用优化标志 -O 编译时。我得到这个输出:

Global value: 300000
Global value: 100000
Global value: 100000
Global value: 100000
Global value: 200000

这部分对我来说没有意义。 GCC 做了哪些优化,使线程在整个 1/3 或 2/3 的总迭代中都获得了竞争条件?

【问题讨论】:

  • 如果您将声明更改为volatile static int global;,您会看到同样的情况吗?
  • global 的声明中添加volatile 限定符,然后重试。这告诉你什么?
  • 未定义的行为是未定义的。您需要查看汇编代码以尝试了解它的作用,也许循环已优化为global += 100000;。但不要指望它有太多意义,你违反了编写正确 C++ 代码的约定,因此编译器无法生成正确的汇编代码。
  • 用 -S 编译两者,自己看看。
  • 您显示的代码仅在主线程末尾打印一次全局值;它无法产生您要求打印 5 个值的输出。我们无法调试您未显示的代码。是的,优化可以改变事物的行为方式。例如,优化器可能会将您的循环减少到 global += 100000;。由于您从不使用 i 并且 global 不是易失性的,这是合法的。

标签: c multithreading gcc optimization


【解决方案1】:

很可能循环已优化为读取全局变量一次,执行所有增量,然后将其写回。输出的差异取决于循环是否重叠。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-27
    • 1970-01-01
    • 2020-12-11
    • 1970-01-01
    相关资源
    最近更新 更多