C++ Valgrind:使用atomic::compare\u exchange\u时,条件跳转或移动取决于未初始化的值

C++ Valgrind:使用atomic::compare\u exchange\u时,条件跳转或移动取决于未初始化的值,c++,multithreading,valgrind,lock-free,C++,Multithreading,Valgrind,Lock Free,我有一个任务来实现一个非常基本的无锁排序向量(只有插入和索引),我让一切都正常工作,但是valgrind说我有一个条件跳转/移动,这取决于一个未初始化的值。我正在使用--track origins=是的,但我觉得它并没有那么有用 这是我的索引运算符的代码: int operator[](int pos) { Pair pdata_old = pdata.load(); Pair pdata_new = pdata_old; // Increment ref count

我有一个任务来实现一个非常基本的无锁排序向量(只有插入和索引),我让一切都正常工作,但是valgrind说我有一个条件跳转/移动,这取决于一个未初始化的值。我正在使用--track origins=是的,但我觉得它并没有那么有用

这是我的索引运算符的代码:

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只是一个包含向量*和int的结构,构造函数初始化它的所有值。我找不到任何依赖未初始化数据的地方,至少通过查看我的代码

下面是相关的valgrind输出(第121行是函数声明所在的行,第130和142行是比较交换弱()行):

==21299==
==21299==线程2:
==21299==条件跳转或移动取决于未初始化的值
==21299==at 0x10A5C2:LFSV::operator[](int)(LFSV.h:130)
==21299==by 0x1099F4:read_position_0()(driver.cpp:27)
==21299==by 0x10FCC6:void std::u invoke_impl(std::u invoke_other,void(*&&)()(invoke.h:60)
==21299==by 0x10FC5C:std::u invoke_result::type std::u invoke(void(*&&)()(invoke.h:95)
==21299==0x10FC34:_ZNSt6thread8_invokerist5tuplejpfveee9_invokeijlm0eedtcsr3stde8_invokespcl10_S_declvalix_eeest12_Index_tupleIJXspT_EEE(线程:234)
==21299==by 0x10FC04:std::thread::u Invoker::operator()(线程:243)
==21299==by 0x10FAE8:std::thread::_State\u impl::_M_run()(线程:186)
==21299==by 0x50FAB9E:execute\u native\u thread\u例程(thread.cc:83)
==21299==by 0x593208B:start_线程(在/usr/lib/libpthread-2.26.so中)
==21299==by0x5c3ee7e:clone(在/usr/lib/libc-2.26.so中)
==21299==未初始化的值是由堆栈分配创建的
==21299==at 0x10A520:LFSV::operator[](int)(LFSV.h:121)
==21299==
==21299==条件跳转或移动取决于未初始化的值
==21299==at 0x10A654:LFSV::operator[](int)(LFSV.h:142)
==21299==by 0x1099F4:read_position_0()(driver.cpp:27)
==21299==by 0x10FCC6:void std::u invoke_impl(std::u invoke_other,void(*&&)()(invoke.h:60)
==21299==by 0x10FC5C:std::u invoke_result::type std::u invoke(void(*&&)()(invoke.h:95)
==21299==0x10FC34:_ZNSt6thread8_invokerist5tuplejpfveee9_invokeijlm0eedtcsr3stde8_invokespcl10_S_declvalix_eeest12_Index_tupleIJXspT_EEE(线程:234)
==21299==by 0x10FC04:std::thread::u Invoker::operator()(线程:243)
==21299==by 0x10FAE8:std::thread::_State\u impl::_M_run()(线程:186)
==21299==by 0x50FAB9E:execute\u native\u thread\u例程(thread.cc:83)
==21299==by 0x593208B:start_线程(在/usr/lib/libpthread-2.26.so中)
==21299==by0x5c3ee7e:clone(在/usr/lib/libc-2.26.so中)
==21299==未初始化的值是由堆栈分配创建的
==21299==at 0x10A520:LFSV::operator[](int)(LFSV.h:121)
==21299==

在带有填充的对象上使用
比较交换
时,这是正常的,不需要担心。它可能会导致虚假的CAS故障,因此,如果您只使用一次而没有重试循环或其他操作,请担心


Pair只是一个包含向量*和int的结构

并在正常的64位C++实现上填充,其中<代码> siZeof(vector *)=8</COD>和<代码> siZeof(int)=4 < /COD>,和<代码>对齐(vector *)=8</Cord> 要使每个指针成员8字节对齐,整个结构/类需要8字节对齐,因此其大小必须填充到8的倍数,以便

Pair foo[]
数组正常工作,每个数组元素具有8字节对齐

但是
比较\u交换\u弱
比较整个对象的位模式,包括填充。

大概您是在没有优化的情况下编译的,编译器为
int
成员创建了一个4字节存储,将局部存储到堆栈中的代码,然后为x86-64的
cmpxchg16b
指令加载两个8字节,将其加载回整个
对,或者(如果
atomic
不是无锁的)获取锁并有效地执行
memcmp

==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==