在 GotW article #45 ,赫伯陈述如下:
void String::AboutToModify(
size_t n,
bool bMarkUnshareable /* = false */
) {
if( data_->refs > 1 && data_->refs != Unshareable ) {
/* ... etc. ... */
This if-condition is not thread-safe. For one thing, evaluating even "data_->refs > 1" may not be atomic; if so, it's possible that if thread 1 tries to evaluate "data_->refs > 1" while thread 2 is updating the value of refs, the value read from data_->refs might be anything -- 1, 2, or even something that's neither the original value nor the new value.
此外,他指出 data_->refs 在与 1 比较和与 Unshareable 比较之间可能会被修改。
进一步,我们找到了解决方案:
void String::AboutToModify(
size_t n,
bool bMarkUnshareable /* = false */
) {
int refs = IntAtomicGet( data_->refs );
if( refs > 1 && refs != Unshareable ) {
/* ... etc. ...*/
现在,我明白两次比较使用相同的引用,解决问题 2。但是为什么使用 IntAtomicGet?我在该主题的搜索中没有找到任何内容 - 所有原子操作都集中在读取、修改、写入操作,而这里我们只是进行读取。那么我们可以做...
int refs = data_->refs;
...最终可能只是一条指令?
最佳答案
不同的平台对读/写操作的原子性做出不同的 promise 。例如,x86
保证读取双字(4 字节
)将是一个原子操作。但是,您不能假设这对于任何架构都是如此,而且很可能不会。
如果您计划将代码移植到不同的平台,这样的假设可能会给您带来麻烦,并导致代码中出现奇怪的竞争条件。因此,最好保护自己并明确使读/写操作原子化。
关于c++ - C++ IntAtomicGet、GotW 的原因,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33246133/