对int变量赋值的操作是原子的吗?

2023-05-28 0 810

具体来说是:

x86编订中,对任何人物理门牌号中的1byte的读总有一天是氢原子的.也是说对两个char的加载总有一天是氢原子的,对物理门牌号翻转2byte的int16类别的加载是氢原子的,对4byte翻转的int32类别读取是氢原子的,从从B90开始,对8byte翻转门牌号的int64加载是氢原子的.因此假如你用的是编订,保证这些要是.但C/C++中又是无穷无尽情境:

C/C++中,C++保证此基础类别的缓存翻转,比如保证double类别的翻转是8(或是4,忘了),

即便是malloc出的也能保证翻转.但是尽管各式各样无可避免的操作方式符切换,比如 char a[4],float* p=(float*)a的存有,使翻转的保证基本上名存实亡.所以,当两个较为长的类别,比如double被C++放进暂存器的这时候,C++国际标准显然不保证再加两条命令就将它放进两个暂存器中.比如我能先把后半部份放进eax,等一会再把后半部份放进edx之类.但是,假如你能保证翻转,所以绝大多数情况下尽管UB,但你的标识符还是有可能恒定工作的.

再接着,只但是下面说的显然不必考量,因为在C/C++国际标准中,两个表达式除采用atomic有关的表达式之外,任何人多处理器同时进行的随机存取事实上都是UB.因此,假如采用国际标准中的atomic机能,或是采用C++便携式的一些扩充,比如InterlockedAdd之类的,不然都是bug的安全隐患.比如,有十分多的开O2以内强化就手忙脚乱的多线程有关标识符是尽管类似于的其原因引致的.

两个很经典之作的范例是两个网路上广为流传的很广的C++的科枫类,下列是这段标识符:

class SingleTon{ public: static SingleTon* getInstance(){ if(NULL == instance){ EnterCriticalSection(&cs); if(NULL == instance){//双检锁,在进入临界区后再检测一次是否对象已经建立 instance = new SingleTon(); } LeaveCriticalSection(&cs); } return instance; } private: static SingleTon* instance; //……………………

这个双检锁的标识符很可能不能恒定工作,因为具体来说是编写者没有告知C++必须假设instance是可能被其他线程改变的,因此C++完全能认为两次if只保留两个要是(当然也可能不会).因此具体来说instance必须改为volatile的,接着是下面所说的子性,instance应该改为atomic<Singleton*>.

C/C++中表达式的氢原子性只但是是个巨大的坑,C++11和C11之前对多处理器的问题几乎只字不提,也没有语言层面对氢原子性的保证,(上文中那段科枫的标识符应该也是C11之前出现的).因此程序员也没有更好的办法,只能采用GCC和VC里便携式的那堆氢原子操作方式,或是懒了就直接不考量这问题了.因此只能写这种有隐含问题的标识符,现在没问题了,大胆用atomic<>吧.

相关文章

发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务