我有两个线程,一个更新一个int,另一个读取它.这是一个统计值,其中读取和写入的顺序无关紧要.
我的问题是,我是否需要同步访问这个多字节值?或者,换句话说,写入的一部分可以完成并被中断,然后读取就会发生.
例如,假设值= 0x0000FFFF,其值递增为0x00010000.
是否有时间值看起来像0x0001FFFF,我应该担心?当然,类型越大,发生这种情况的可能性就越大.
我总是同步这些类型的访问,但很好奇社区的想法.
男孩,真是个问题.答案是:
是的,不,嗯,这取决于
这一切都归结为系统的架构.在IA32上,正确对齐的地址将是原子操作.未对齐的写入可能是原子的,它取决于正在使用的缓存系统.如果内存位于单个L1缓存行中,则它是原子的,否则不是.CPU和RAM之间的总线宽度会影响原子性质:8086上正确对齐的16位写入是原子的,而8088上的相同写入不是因为8088只有8位总线而8086有16位总线.
此外,如果您正在使用C/C++,请不要忘记将共享值标记为volatile,否则优化器会认为该变量永远不会在您的某个线程中更新.
起初人们可能认为本机大小的读取和写入是原子的,但是有许多问题要处理,包括处理器/核心之间的高速缓存一致性.在Windows上使用Interlocked*等原子操作,在Linux上使用等效操作.C++ 0x将有一个"原子"模板将它们包装在一个漂亮的跨平台接口中.目前,如果您使用的是平台抽象层,它可能会提供这些功能. ACE确实如此,请参阅类模板ACE_Atomic_Op.
如果您正在读/写4字节值并且它在内存中是DWORD对齐的并且您在I32架构上运行,那么读取和写入都是原子的.
是的,您需要同步访问.在C++ 0x中,它将是一个数据争用和未定义的行为.使用POSIX线程,它已经是未定义的行为.
实际上,如果数据类型大于本机字大小,则可能会得到错误的值.此外,由于优化移动读取和/或写入,另一个线程可能永远不会看到写入的值.