这是自动读写bool类型的正确方法吗?
Is this the correct way to atomically read and write a bool?
布尔标志由两个线程切换。下面的代码有意义吗?
static bool ATOMIC_BOOL_READ( volatile bool& var )
{
return __sync_fetch_and_or(&var, 0);
}
static void ATOMIC_BOOL_WRITE(volatile bool& var, bool newval )
{
__sync_bool_compare_and_swap( &var, !newval, newval);
}
注意以下几点:
我正在传递一个bool引用。有意义吗?
为了踢的缘故,我也声明它是易失的。
- 函数是静态的
我想问的基本问题是:原子性和内存屏障之间的区别是什么?如果线程A正在对变量foo执行原子内置,那么线程B不能对变量foo做任何事情;因此制造了一个内存障碍?
只读-修改-写操作族只需要原子。隔离的读和写已经是原子的了。
你的问题说两个线程"切换"相同的bool。这不是你发布的函数所做的——如果你把这些函数组合起来执行切换,它仍然不是线程安全的。
为什么不使用std::atomic_int
?
i=0;
是线程安全的,i=i+1;
不是,因为如果另一个线程在同一时间做同样的事情,i
可能最终只增加一次而不是两次。这是一个读-修改-写,一个示例问题序列是线程1和线程2的(read1,read2,modify1,write1,modify2,write2)
。到目前为止,一切都很标准。
现在你可以看到为什么这也不是线程安全的吗?
bool x = ATOMIC_BOOL_READ (&b);
x = !x;
ATOMIC_BOOL_WRITE (&b, x);
你的函数增加了没有线程安全。你可以写一个函数
bool atomic_toggle_and_return_new_value (bool * b) { ... }
基于比较-交换或测试-设置。对于更复杂的情况,即"两个线程都读写相同的 bool",则需要读写器在某些临界区上协作同步(或者查看无锁和无等待算法)。
__sync_bool_compare_and_swap
是正确的,但可能比必要时贵得多。
这取决于你需要什么。__sync_lock_test_and_set
将更便宜(并且保证是原子的),但是它不会报告操作是否"成功",只要值是预期的(无论如何它总是"成功",并且您也确实获得了值,如果它不是您所说的,它只是不会失败)。然而,这是一些并不总是有趣的信息。
如果您在c++ 0x模式下编译,则可以使用std::atomic<bool>
而不是原子内置,该模式提供了.load()
和.store()
。这些函数可能更有效(或者利用某些操作是原子性的知识,或者插入屏障,或者使用特殊操作,或者其他什么),并且您的代码更易于移植(并且更明显)。
此外,在几乎所有的体系结构中,您还可以期望(尽管不能保证!)写bool是原子的。
…这要看情况。例如,如果你只想在一个线程中设置一个标志,并且只想看看它是否在另一个线程中设置,并且在实现之前可能需要几微秒并不重要,那么你可以直接分配变量,而不考虑任何原子性。
Atomics本质上是不可移植的,这些是将来可能不再存在的GCC扩展,并且不能在其他编译器上工作。
只有当你完全理解了上面的陈述后,你才能阅读答案的其余部分。
一个值得注意的事实是,现有的所有机器总是保证对特定大小的数据的访问是原子的。这源于这样一个基本概念:内存和系统总线中的数据以一定的粒度传输。在大多数机器中,布尔值应该是原子值,因此:bool ATOMIC_BOOL_READ(volatile bool* b) {
bool v = *b;
__sync_synchronize(); // ensure value pushed to memory
return v;
}
void ATOMIC_BOOL_WRITE(volatile bool* b, bool v) {
__sync_synchronize(); // read will return fresh value
*b = v;
}
这可能就是为什么GCC不提供简单的加载/存储特殊原子操作的原因:它们已经被认为是原子的。
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗
- 有没有一种方法可以通过"typedef"为重新定义的基本类型定义特征和强制转换运算符
- 当无法使用模板和宏时,生成类型变体C++代码的最简单方法是什么?
- 是否有内置方法可以强制转换为不同的基础类型,但保留常量限定符?
- 拥有映射的现代方法,该映射可以指向或引用已在堆栈上分配的不同类型的数据
- 类作用域的类型别名"using":[何时]方法中的用法可以先于类型别名?
- 调用具有未标识类型的类的方法
- 将复杂的非基元C++数据类型转换为 Erlang/Elixir 格式,以使用 NIF 导出方法
- 我的模板类方法返回错误类型?
- 在 C++ 中将非指定类型作为参数传递的最佳方法?
- QtQuick - qml:28:错误:未知方法返回类型:自定义类型
- 构造智能点数据类型以及普通数据类型的通用方法
- 如何在没有实例的情况下获取非静态方法的类型?
- C++方法是否可以根据传递给构造函数的参数具有不同的返回类型?
- 在自定义 std::vector-like 容器中处理指针和非指针模板类型的最佳方法是什么?
- 使用类型id运算符的最佳替代方法
- 检查子类型时的专用方法模板
- C ++类型特征:确保子类实现方法
- 标识派生类类型的正确方法(类型实体VS dynamic_case)
- 类方法类型的decltype