简单的C程序来说明无序执行?
我正在运行x86,我想实际看到一个错误,它是由我的机器上的无序执行引起的。我试着写了一篇,但我总是看到“x的值是33”:简单的C程序来说明无序执行?,c,multithreading,x86,memory-barriers,C,Multithreading,X86,Memory Barriers,我正在运行x86,我想实际看到一个错误,它是由我的机器上的无序执行引起的。我试着写了一篇,但我总是看到“x的值是33”: #包括 #包括 #包括 int x,f; void*handler(void*ptr){ 而(f==0); //期望值:有时,由于exec出现故障,应该打印11 printf(“x的值为%d\n”,x); 返回NULL; } int main(){ pthread_t thread1; 而(1){ x=11;f=0; pthread_create(&thread1,NULL,
#包括
#包括
#包括
int x,f;
void*handler(void*ptr){
而(f==0);
//期望值:有时,由于exec出现故障,应该打印11
printf(“x的值为%d\n”,x);
返回NULL;
}
int main(){
pthread_t thread1;
而(1){
x=11;f=0;
pthread_create(&thread1,NULL,handler,NULL);
x=33;
f=1;
pthread_join(thread1,NULL);
}
返回0;
}
什么是最简单的c程序,可以说明一个无序的执行错误?为什么有时不打印“x的值为11”您试图创建的效果并不依赖于无序执行。这只是可以创建内存重新排序的因素之一。此外,现代x86执行时会出现无序,但它使用内存顺序缓冲区来确保提交到L1d/的存储以程序顺序全局可见。(因为x86的内存模型只允许StoreLoad重新排序,而不允许StoreStore。) 内存重新排序与指令执行重新排序是分开的,因为即使按顺序CPU也使用存储缓冲区来避免缓存未命中存储暂停
如果
x
和f
在不同的缓存线中结束,则顺序ARM CPU上的C实现可以打印11或33。
我假设您在编译时禁用了优化功能,因此编译器会有效地处理所有变量
volatile
,即volatile int x,f
。否则,while(f==0)如果(f==0){infloop;}
,则代码>循环将编译为,只检查f
一次。(非原子变量的数据竞争允许编译器从循环中提升负载,但volatile
负载必须始终完成。)
生成的asm/机器代码中的存储将以C源代码顺序显示
您是为x86编译的,它有一个强大的内存模型:x86存储是发布存储,x86加载是获取加载。您不能获得顺序一致性,但可以免费获得acq_rel。(对于未优化的代码,即使您不要求,也会发生这种情况。)
因此,在没有针对x86进行优化的情况下编译时,您的程序相当于
_Atomic int x, f;
int main(){
...
pthread_create
atomic_store_explicit(&x, 33, memory_order_release);
atomic_store_explicit(&f, 1, memory_order_release);
...
}
负载侧也是如此。while(f==0){}
是x86上的一个获取负载,因此让读取端等待直到它看到非零的f
可以保证它也看到x==33
但是,如果您为弱顺序的ISA(如ARM或PowerPC)编译,asm级别的内存排序保证确实允许StoreStore和LoadLoad重新排序,因此,如果编译时未进行优化,您的程序可能会打印11
另请参见线程启动不够快。只需在主函数中创建一个sleep()
即可获得您的11值。另一种方法是(可能)在系统中加载一些CPU密集型进程,以更改取消竞争condition@Jean-Françoisfab但是handler
在f=1之前什么都不做代码>已完成,此时x=33代码>已经完成。@Jean-Françoisfare不认为这里有比赛条件。@kiranBiradar在(f==0)退出之后代码>约束,如果您多次运行程序,时间片调度将分离pthread\u create(&thread1,NULL,handler,NULL)代码>从x=33
并在裂缝中运行处理程序
,以报告11
。
_Atomic int x, f;
int main(){
...
pthread_create
atomic_store_explicit(&x, 33, memory_order_release);
atomic_store_explicit(&f, 1, memory_order_release);
...
}