C++11 多线程:Valgrind 未初始化值警告
C++11 multithreading: Valgrind uninitialized value(s) warning
我使用 gcc 8.2.1 在 Linux 下编译了以下虚拟程序:
#include <iostream>
#include <mutex>
#include <thread>
struct Foo
{
void start() {
thread = std::thread(&Foo::run, this);
}
void stop() {
mutex.lock();
done = true;
mutex.unlock();
thread.join();
}
void run() {
bool tmp;
for (;;) {
mutex.lock();
tmp = done;
mutex.unlock();
if (tmp)
break;
}
}
std::thread thread;
std::mutex mutex;
bool done;
};
int main()
{
Foo foo;
std::cout << "starting...\n";
foo.start();
std::cout << "stopping...\n";
foo.stop();
std::cout << "done\n";
}
如果我随后在 valgrind 3.14.0 下 运行 它,我会收到以下警告:
==30060== Thread 2:
==30060== Conditional jump or move depends on uninitialised value(s)
==30060== at 0x1095F3: Foo::run() (in /.../a.out)
==30060== by 0x109AAE: void std::__invoke_impl<void, void (Foo::*)(), Foo*>(std::__invoke_memfun_deref, void (Foo::*&&)(), Foo*&&) (in /.../a.out)
==30060== by 0x109771: std::__invoke_result<void (Foo::*)(), Foo*>::type std::__invoke<void (Foo::*)(), Foo*>(void (Foo::*&&)(), Foo*&&) (in /.../a.out)
==30060== by 0x10A012: decltype (__invoke((_S_declval<0ul>)(), (_S_declval<1ul>)())) std::thread::_Invoker<std::tuple<void (Foo::*)(), Foo*> >::_M_invoke<0ul, 1ul>(std::_Index_tuple<0ul, 1ul>) (in /.../a.out)
==30060== by 0x109FB8: std::thread::_Invoker<std::tuple<void (Foo::*)(), Foo*> >::operator()() (in /.../a.out)
==30060== by 0x109F8D: std::thread::_State_impl<std::thread::_Invoker<std::tuple<void (Foo::*)(), Foo*> > >::_M_run() (in /.../a.out)
==30060== by 0x496A062: execute_native_thread_routine (thread.cc:80)
==30060== by 0x4894A9C: start_thread (in /usr/lib/libpthread-2.28.so)
==30060== by 0x4CD7A42: clone (in /usr/lib/libc-2.28.so)
我不完全确定是什么原因造成的,我写了这个片段希望能诊断出一个更复杂的错误 class(我不能在这里 post)我目前正在工作on 和 which 在调用 Foo::stop()
的等效项时会产生异常。 valgrind 警告是否意味着我对 C++ 线程接口有一些严重的误解?暂时假设 Foo::run
实际上会做一些有用的事情,我怎样才能在保持 Foo
的界面不变的同时修复这个程序?
bool done;
的初始值是多少?它是不确定的(一些垃圾值),因此您的线程 (run
) 可以在不调用 stop
方法的情况下停止。
done
必须初始化:
//...
std::mutex mutex;
bool done = false; // <--
我使用 gcc 8.2.1 在 Linux 下编译了以下虚拟程序:
#include <iostream>
#include <mutex>
#include <thread>
struct Foo
{
void start() {
thread = std::thread(&Foo::run, this);
}
void stop() {
mutex.lock();
done = true;
mutex.unlock();
thread.join();
}
void run() {
bool tmp;
for (;;) {
mutex.lock();
tmp = done;
mutex.unlock();
if (tmp)
break;
}
}
std::thread thread;
std::mutex mutex;
bool done;
};
int main()
{
Foo foo;
std::cout << "starting...\n";
foo.start();
std::cout << "stopping...\n";
foo.stop();
std::cout << "done\n";
}
如果我随后在 valgrind 3.14.0 下 运行 它,我会收到以下警告:
==30060== Thread 2:
==30060== Conditional jump or move depends on uninitialised value(s)
==30060== at 0x1095F3: Foo::run() (in /.../a.out)
==30060== by 0x109AAE: void std::__invoke_impl<void, void (Foo::*)(), Foo*>(std::__invoke_memfun_deref, void (Foo::*&&)(), Foo*&&) (in /.../a.out)
==30060== by 0x109771: std::__invoke_result<void (Foo::*)(), Foo*>::type std::__invoke<void (Foo::*)(), Foo*>(void (Foo::*&&)(), Foo*&&) (in /.../a.out)
==30060== by 0x10A012: decltype (__invoke((_S_declval<0ul>)(), (_S_declval<1ul>)())) std::thread::_Invoker<std::tuple<void (Foo::*)(), Foo*> >::_M_invoke<0ul, 1ul>(std::_Index_tuple<0ul, 1ul>) (in /.../a.out)
==30060== by 0x109FB8: std::thread::_Invoker<std::tuple<void (Foo::*)(), Foo*> >::operator()() (in /.../a.out)
==30060== by 0x109F8D: std::thread::_State_impl<std::thread::_Invoker<std::tuple<void (Foo::*)(), Foo*> > >::_M_run() (in /.../a.out)
==30060== by 0x496A062: execute_native_thread_routine (thread.cc:80)
==30060== by 0x4894A9C: start_thread (in /usr/lib/libpthread-2.28.so)
==30060== by 0x4CD7A42: clone (in /usr/lib/libc-2.28.so)
我不完全确定是什么原因造成的,我写了这个片段希望能诊断出一个更复杂的错误 class(我不能在这里 post)我目前正在工作on 和 which 在调用 Foo::stop()
的等效项时会产生异常。 valgrind 警告是否意味着我对 C++ 线程接口有一些严重的误解?暂时假设 Foo::run
实际上会做一些有用的事情,我怎样才能在保持 Foo
的界面不变的同时修复这个程序?
bool done;
的初始值是多少?它是不确定的(一些垃圾值),因此您的线程 (run
) 可以在不调用 stop
方法的情况下停止。
done
必须初始化:
//...
std::mutex mutex;
bool done = false; // <--