我有一个任务来实现一个非常基本的无锁排序向量(仅具有插入和索引功能),并且一切正常,但是,valgrind表示我有条件地跳转/移动,具体取决于未初始化的值。我使用的是--track-origins = yes,但是我发现这并不是很有帮助。
这是我的索引运算符的代码:
int operator[](int pos) {
Pair pdata_old = pdata.load();
Pair pdata_new = pdata_old;
// Increment ref count
do {
pdata_new = pdata_old;
++pdata_new.ref_count;
} while (!pdata.compare_exchange_weak(pdata_old, pdata_new));
// Get old data
int ret_val = (*pdata_new.pointer)[pos];
pdata_old = pdata.load();
// Decrement ref count
do {
pdata_new = pdata_old;
--pdata_new.ref_count;
// assert(pdata_new.ref_count >= 0);
} while (!pdata.compare_exchange_weak(pdata_old, pdata_new));
return ret_val;
}
Pair只是一个包含vector *和int的结构,构造函数初始化其所有值。我找不到任何依赖未初始化数据的地方,至少仅通过查看我的代码即可。
这是相关的valgrind输出(第121行是在其上声明函数的行,第130和142是compare_exchange_weak()行):
==21299==
==21299== Thread 2:
==21299== Conditional jump or move depends on uninitialised value(s)
==21299== at 0x10A5C2: LFSV::operator[](int) (lfsv.h:130)
==21299== by 0x1099F4: read_position_0() (driver.cpp:27)
==21299== by 0x10FCC6: void std::__invoke_impl<void, void (*)()>(std::__invoke_other, void (*&&)()) (invoke.h:60)
==21299== by 0x10FC5C: std::__invoke_result<void (*)()>::type std::__invoke<void (*)()>(void (*&&)()) (invoke.h:95)
==21299== by 0x10FC34: _ZNSt6thread8_InvokerISt5tupleIJPFvvEEEE9_M_invokeIJLm0EEEEDTclsr3stdE8__invokespcl10_S_declvalIXT_EEEEESt12_Index_tupleIJXspT_EEE (thread:234)
==21299== by 0x10FC04: std::thread::_Invoker<std::tuple<void (*)()> >::operator()() (thread:243)
==21299== by 0x10FAE8: std::thread::_State_impl<std::thread::_Invoker<std::tuple<void (*)()> > >::_M_run() (thread:186)
==21299== by 0x50FAB9E: execute_native_thread_routine (thread.cc:83)
==21299== by 0x593208B: start_thread (in /usr/lib/libpthread-2.26.so)
==21299== by 0x5C3EE7E: clone (in /usr/lib/libc-2.26.so)
==21299== Uninitialised value was created by a stack allocation
==21299== at 0x10A520: LFSV::operator[](int) (lfsv.h:121)
==21299==
==21299== Conditional jump or move depends on uninitialised value(s)
==21299== at 0x10A654: LFSV::operator[](int) (lfsv.h:142)
==21299== by 0x1099F4: read_position_0() (driver.cpp:27)
==21299== by 0x10FCC6: void std::__invoke_impl<void, void (*)()>(std::__invoke_other, void (*&&)()) (invoke.h:60)
==21299== by 0x10FC5C: std::__invoke_result<void (*)()>::type std::__invoke<void (*)()>(void (*&&)()) (invoke.h:95)
==21299== by 0x10FC34: _ZNSt6thread8_InvokerISt5tupleIJPFvvEEEE9_M_invokeIJLm0EEEEDTclsr3stdE8__invokespcl10_S_declvalIXT_EEEEESt12_Index_tupleIJXspT_EEE (thread:234)
==21299== by 0x10FC04: std::thread::_Invoker<std::tuple<void (*)()> >::operator()() (thread:243)
==21299== by 0x10FAE8: std::thread::_State_impl<std::thread::_Invoker<std::tuple<void (*)()> > >::_M_run() (thread:186)
==21299== by 0x50FAB9E: execute_native_thread_routine (thread.cc:83)
==21299== by 0x593208B: start_thread (in /usr/lib/libpthread-2.26.so)
==21299== by 0x5C3EE7E: clone (in /usr/lib/libc-2.26.so)
==21299== Uninitialised value was created by a stack allocation
==21299== at 0x10A520: LFSV::operator[](int) (lfsv.h:121)
==21299==
compare_exchange_weak
在带padding的对象上使用时,这是正常现象,无需担心。这可能会导致伪造的CAS故障,因此请担心是否compare_exchange_strong
只使用一次而没有重试循环等。
Pair只是一个包含vector *和int的结构
因此,对普通的64位C ++实现(其中sizeof(vector*) == 8
和sizeof(int) == 4
和)进行了填充alignof(vector*) == 8
。
为了使每个指针成员8字节对齐,需要将整个struct / class对齐8,因此必须将其大小填充为8的倍数,以便一个数组Pair foo[]
正常工作,每个数组元素具有8字节对齐。
但是compare_exchange_weak
比较整个对象的位模式,包括填充。
大概你不优化编译,编译器做代码存储当地人堆栈与4字节存储的int
成员,但随后将其加载回整Pair
2个8字节的负载为X86-64的cmpxchg16b
指令,或者(如果atomic<Pair>
ISN (不是无锁)进行锁定并有效地执行memcmp
。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句