c++使用IntAtomicGet的原因
Reason for C++ IntAtomicGet, GotW
在GotW的第45篇文章中,Herb陈述如下:
void String::AboutToModify(
size_t n,
bool bMarkUnshareable /* = false */
) {
if( data_->refs > 1 && data_->refs != Unshareable ) {
/* ... etc. ... */
这个if条件不是线程安全的。首先,即使计算"data_->refs> 1"也可能不是原子性的;如果是这样,如果线程1试图计算"data__ ->refs> 1",而线程2正在更新refs的值,那么从data__ ->refs读取的值可能是任何值——1、2,甚至既不是原始值也不是新值。
此外,他指出data_->ref可能在与1比较和与Unshareable比较之间被修改。
再往下,我们找到了一个解决方案:
void String::AboutToModify(
size_t n,
bool bMarkUnshareable /* = false */
) {
int refs = IntAtomicGet( data_->refs );
if( refs > 1 && refs != Unshareable ) {
/* ... etc. ...*/
现在,我明白了两个比较使用了相同的refs,解决了问题2。但是为什么要使用IntAtomicGet?我在这个主题的搜索中没有找到任何东西——所有的原子操作都集中在读、修改、写操作上,这里我们只有一个读操作。所以我们能不能…
int refs = data_->refs;
…这应该是最后的一个指令?
不同的平台对读/写操作的原子性做出了不同的承诺。例如,x86
保证读取双字(4 bytes
)将是一个原子操作。但是,您不能假设这对任何体系结构都是正确的,而且很可能不是。
如果您计划将代码移植到不同的平台,这样的假设可能会给您带来麻烦,并导致代码中出现奇怪的竞争条件。因此,最好保护自己,并显式地使读/写操作原子化。
当另一个线程写入共享内存(data_->refs
)时,从它读取数据是数据竞争的定义。
当我们非原子地从data_->refs
读取而另一个线程同时试图写入它时会发生什么?
假设线程A正在执行++data_->refs
(写),而线程B正在执行int x = data_->refs
(读)。想象一下,线程B从data_->refs
读取前几个字节,线程A在线程B完成读取之前将其值写入data_->refs
。然后线程B读取data_->refs
处的剩余字节。
您既不会得到原始值,也不会得到新值;你会得到一个完全不同的价值!这个场景只是为了说明:
是什么意思[…从data__ ->refs中读取的值可以是任何值——1、2或即使不是原值也不是新值
原子操作的目的是确保操作是不可分割的:它要么被观察到已完成,要么被观察到未完成。因此,我们使用原子读操作来确保我们在data_->refs
更新之前或之后获得它的值(这取决于线程计时)。
- 如何创建一个CMake变量,除非显式重写,否则使用默认值
- C++:TypeDef使用元组
- 使用std::multimap迭代器创建std::list
- 从不同线程使用int64的不同字节安全吗
- 比较并显示使用最小值(a,b)和最大值(a、b)升序排列的4个数字
- 为什么在全局范围内使用"extern int a"似乎不行?
- 在C#中处理C++指针而不使用unsafe的最佳方法
- 使用C++库在Android项目中修改gradle中的cmake参数,用于插入指令的测试
- 如何使用Google Mock来模拟gettimeofday()
- 如何使用默认参数等选择模板专业化
- 为什么使用 "this" 指针调用派生成员函数?
- 使用新行和不使用新行读取文件
- 如何使用 < 和 > 命令获取 c++ 中的输入和输出?
- 如何确定我已使用非编码文件到达 EOF?
- 如何在cuSparse中使用cusparseXcoo2csr从coo转换为csc
- 使用CMake创建QML插件
- 使用strcpy将char数组的元素复制到另一个数组
- 在c++中使用nlohmann从类到json的转换
- 使用指针从C++中的数组中获取最大值
- c++使用IntAtomicGet的原因