将 std::atomic_flag 包裹在吸气剂/二传手中会使它的"atomicity"无效吗?
Does wrapping a std::atomic_flag in a getter/setter void its "atomicity"?
说我有一个包含std::atomic_flag
作为私人成员的类,通过getter暴露。类似以下内容(伪代码(:
class Thing
{
private:
std::atomic_flag ready = ATOMIC_FLAG_INIT;
public:
isReady()
{
return ready.test_and_set();
}
}
我的天真问题是:是否通过方法查询标志将其转化为非原子操作,是函数调用非原子(还是它?(?我应该让我的ready
标志成为公共成员并直接查询吗?
不,不是。test_and_set()
操作本身是原子,因此不同的呼叫堆栈有多深都没关系。
要证明这一点,请考虑直接"暴露" atomic_flag
对象的基本情况:
static atomic_flag flag = ATOMIC_FLAG_INIT;
void threadMethod() {
bool wasFirst = !flag.test_and_set();
if( wasFirst ) cout << "I am thread " << this_thread::get_id() << ", I was first!" << endl;
else cout << "I am thread " << this_thread::get_id() << ", I'm the runner-up" << endl;
}
如果两个线程输入 threadMethod
-稍微稍微( t1
(在另一个线程(t2
(之前(CC_7(,那么我们可以期望控制台输出为以下(以相同的顺序(:
I am thread t1, I was first!
I am thread t2, I'm the runner-up
现在,如果这两个线程同时输入,但是t2
比t1
领先微秒,但是t2
然后比t1
慢,因为它撰写了STDOUT,则输出将是:
I am thread t1, I'm the runner-up
I am thread t2, I was first!
...因此,即使输出不一定按预期顺序,对test_and_set
的调用仍然是原子。
现在,如果您要用另一种方法将flag
包装(不夹住,只是为了确定(,例如...
__declspec(noinline)
bool wrap() {
return !flag.test_and_set();
}
void threadMethod() {
bool wasFirst = wrap();
if( wasFirst ) cout << "I am thread " << this_thread::get_id() << ", I was first!" << endl;
else cout << "I am thread " << this_thread::get_id() << ", I'm the runner-up" << endl;
}
...那么该程序的行为不会有所不同 - 因为false
或true
返回test_and_set()
的CC_17值仍将在每个线程的堆栈中。ergo,包装atomic_flag
不会改变其原子。
C 原子的原子性属性确保中间不能破坏操作。也就是说,对于观察原子的第二个线程,它将在test_and_set
之前观察状态或test_and_set
之后的状态。这样的线程不可能在test
和set
零件之间偷偷摸摸。
但是,这仅适用于操作本身。test_and_set
呼叫完成后,所有赌注又一次关闭。您应该始终假设执行test_and_set
的线程在完成该指令后可能会立即被预先享用,因此您不能假设在test_and_set
之后执行的任何指令仍然会观察到相同的状态。
因此,添加函数调用不会在这里陷入困境。原子上的任何指令都必须假设原子变量的状态在此期间可能已经改变。Atomics通过提供以特殊方式设计的接口来考虑到这一点:例如,test_and_set
返回测试结果,因为通过单独的调用获得该信息将不再是原子。
no, isReady()
方法的工作原子与直接test_and_set()
完全相同。
- Openssl 1.1.1d无效使用不完整的类型"struct dsa_st"
- 无法访问嵌套类.类的使用无效
- 如果用户输入无效,如何使用字符串变量-C++重复输入命令
- 如何解决错误:SCIP C++中的 SCIP 阶段无效 <10>
- 在没有参数列表的情况下使用模板名称"Event"无效,模板问题
- FFMPEG配置文件级别id大小无效
- 错误:从"int"到枚举c++的转换无效
- 如何修复此错误:className::className的无效使用
- 为什么将值返回函数传递给重载=运算符对运算符函数有效,而对其他运算符无效
- C++-模板嵌套类的引用初始化无效
- 错误:无效的预处理指令 #i 的意思是 #if?
- 多维数组 C++ 中数组下标的类型"int[int]"无效
- 在 C++ 中使用正则表达式错误时出现问题 括号表达式中的范围无效
- 从 'int' 到 'int*' CPP 的转换无效
- 如何接受 [ENTER] 键作为无效输入并发送错误消息
- 由于无效的 ValidateRgn() 子窗口不会收到WM_PAINT消息
- C++ PTHREADS - 无效转换无效*(*)()到无效*(*)(无效*)
- 声明为无效的变量或字段'...' Ardunio 编译器上的错误
- 数组下标的类型"float*[float]"无效
- 将 std::atomic_flag 包裹在吸气剂/二传手中会使它的"atomicity"无效吗?