因为诸如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()
的副作用。请注意,如果有执行全局优化的编译器可以推断出未在其他地方使用的,它们可能会延迟或忽略分配。但是,在这种情况下,没有其他任何东西使用副作用,所以不会有问题。a
1
pthread_create()
a