2

AFAIK 有充当内存屏障的 pthread 函数(例如,此处clarifications-on-full-memory-barriers-involved-by-pthread-mutexes)。但是编译时障碍呢,即编译器(尤其是 gcc)是否意识到这一点?
换句话说 - 例如 - pthread_create() 是 gcc 不执行重新排序的原因吗?

例如在代码中:

a = 1;
pthread_create(...);

是否确定不会进行重新排序?
来自不同函数的调用怎么样:

void fun(void) {
    pthread_create(...);
    ...
}

a = 1;
fun();

fun() 是否也编译时间障碍(假设 pthread_create() 是)?
不同翻译单元的功能如何?

请注意,我对一般 gcc 和 pthreads 行为规范感兴趣,不一定是特定于 x86 的(关注各种不同的嵌入式平台)。
我也对其他编译器/线程库的行为不感兴趣。

4

1 回答 1

3

因为诸如pthread_create()外部函数之类的函数,编译器必须确保在调用函数之前必须完成对外部函数可见的任何副作用(例如对全局变量的写入)。a在第一种情况下,直到函数调用之后,编译才能对写入重新排序)假设a是全局的或可能在外部可访问)。

这是任何 C 编译器所必需的行为,并且与线程几乎没有关系。

但是,如果变量a是局部变量,编译器可能能够重新排序它,直到函数调用之后(a甚至可能根本不会在内存中结束),除非类似的地址a被获取并在外部可用以某种方式(例如将其作为线程参数传递)。

例如:

int a;

void foo(void)
{
    a = 1;
    pthread_create(...);    // the compiler can't reorder the write to `a` past 
                            //  the call to `pthread_create()`

    // ...
}


void bar(void)
{
    int b;
    b = 1;
    pthread_create(...);    // `b` can be initialized after calling `pthread_create()`
                            // `b` might not ever even exist except as a something
                            //  passed on the stack or in a register to `printf()`

    printf( "%d\n", b);
}

我不确定是否有文档更详细地概述了这一点——这在很大程度上被 C 的“好像”规则所涵盖。在 5.1.2.3/3“程序执行”中的 C99 中。C 由具有序列点的抽象机器指定,其中副作用必须完整,并且程序必须遵循该抽象机器模型,除非编译器可以推断出不需要副作用。

在我foo()上面的示例中,编译器通常无法推断出a = 1;不需要设置,因此必须在调用之前完成设置值pthread_create()的副作用。请注意,如果有执行全局优化的编译器可以推断出未在其他地方使用的,它们可能会延迟或忽略分配。但是,在这种情况下,没有其他任何东西使用副作用,所以不会有问题。a1pthread_create()a

于 2012-11-24T19:35:16.013 回答