根据OpenMP规范(v4.0),由于i的不同步读/写,以下程序包含可能的数据竞争:inti{0};//std::atomici{0};voidwrite(){//#pragmaompatomicwrite//seq_csti=1;}intread(){intj;//#pragmaompatomicread//seq_cstj=i;returnj;}intmain(){#pragmaompparallel{/*codethatcallsbothwrite()andread()*/}}我想到的可能的解决方案在代码中显示为注释:保护i的读写与#pragmaompatomicwrite/re
AFAIKC++原子()系列提供3个好处:原始指令不可分割性(无脏读),内存排序(CPU和编译器)和跨线程可见性/更改传播。我不确定第三个项目符号,因此请看下面的示例。#includestd::atomic_boola_flag=ATOMIC_VAR_INIT(false);structData{intx;longlongy;charconst*z;}data;voidthread0(){//dueto"release"thedatawillbewrittentomemory//exactlyinthefollowingorder:x->y->zdata.x=1;data.y=100;
与C++11相比,OpenMP从内存操作而非变量的角度处理原子性。例如,这允许在编译时对存储在大小未知的vector中的整数使用原子读/写:std::vectorv;//non-atomicaccess(e.g.,inasequentialregion):v.resize(n);...v.push_back(i);...//atomicaccessinamulti-threadedregion:#pragmaompatomicwrite//seq_cstv[k]=...;#pragmaompatomicread//seq_cst...=v[k];在C++11中,这是不可能实现的。我们可
一个代码库有一个COMPILER_BARRIER宏定义为__asm__volatile("":::"memory").宏的目的是防止编译器跨屏障重新排序读写。请注意,这显然是编译器屏障,不是处理器级内存屏障。事实上,这是相当可移植的,因为在AssemblerTemplate中没有实际的汇编指令,只有volatile和memory破坏。因此,只要编译器支持GCC的ExtendedAsm语法,它就应该可以正常工作。不过,我很好奇如果可能的话,在C++11原子API中表达这一点的正确方法是什么。以下似乎是正确的想法:atomic_signal_fence(memory_order_acq_r
考虑以下程序:inti{0};std::experimental::barrierb{2};intmain(){std::threadt0{[]{b.arrive_and_wait();std::cout即使i不是原子变量,这个程序是否保证打印出2?根据cppreference:Callstoarrive_and_waitsynchronizeswiththestartofthecompletionphaseofthebarrier.Thecompletionofthecompletionphasesynchronizeswiththereturnfromthecall.Callsto
在VisualC++2013上,当我编译以下代码时#includeintmain(){std::atomicv(2);returnv.fetch_add(1,std::memory_order_relaxed);}我在x86上取回了以下程序集:51pushecxB802000000moveax,28D0C24leaecx,[esp]8701xchgeax,dwordptr[ecx]B801000000moveax,1F00FC101lockxadddwordptr[ecx],eax59popecxC3ret在x64上类似:B802000000moveax,287442408xchgea
我对多线程很感兴趣。该领域有很多陷阱,例如,不能保证指针写入是原子的。我明白了,但想知道在实际情况下最流行的当前配置是什么?例如,在我的MacbookPro/gcc上,指针写入看起来绝对是原子的。 最佳答案 这主要是指针宽度大于CPU架构宽度的CPU架构的问题。例如,在ATmega上CPU,8位架构,地址空间是16位。如果没有任何特定指令来加载和存储16位地址,则至少需要两条指令来加载/存储指针值。 关于c++-指针写入不是原子的最常见配置是什么?,我们在StackOverflow上找到
arrayA;atomic_init(A,{0})和A={ATOMIC_VAR_INIT(0)}似乎都不起作用,返回了一个难以理解的错误。如何将原子数组初始化为0?即使for循环在每一步都更新数组的一个元素也是行不通的。如果我们无法初始化原子数组,它们的用途是什么?我还想补充一点,我的数组的实际大小很大(不是示例中的10),所以我需要直接初始化。 最佳答案 std::array,100>A;for(auto&x:A)std::atomic_init(&x,std::size_t(0));做这个工作使用clang++-std=c++1
想象一个有两个线程的程序。他们正在运行以下代码(CAS指的是CompareandSwap)://Visibletoboththreadsstaticinttest;//RunbythreadAvoidfoo(){//Checkifvalueis'test'andswapin0xdeadbeefwhile(!CAS(&test,test,0xdeadbeef)){}}//RunbythreadBvoidbar(){while(1){//Perpetuallyatomicallywriterand()intothetestvariableatomic_write(&test,rand())
如果我一次性声明并定义一个原子指针,比如-std::atomiciptr=newint(1);std::atomiciptr=newT();据我了解,整个操作不是原子的。newT()涉及分配内存,构造T对象,然后自动分配给iptr。T可能很容易构造,在这种情况下,构造T不应抛出异常,但某些用户定义的T可能会抛出异常。如果在T构造或内存分配之间某个其他线程使用iptr怎么办?这个操作真的是原子的吗?使其成为原子的一种方法是打破声明和定义,例如T*temp=newT();std::atomiciptr=temp;有没有其他方法可以原子地做同样的事情?我的理解有问题吗?