【发布时间】:2021-10-18 20:44:04
【问题描述】:
在执行 thread sanitizer 测试期间,我注意到一些让我有点担心的事情(可能更多是因为缺乏理解)。
下面的调用堆栈部分表示线程清理器检测到的数据竞争:
Previous write of size 8 at 0x7b4400020080 by thread T4 (mutexes: write M258529629327854840):
#0 malloc <null> (libtsan.so.0+0x2cbe2)
...
#11 std::thread::_Invoker<std::tuple<void (MyCustomWorker::*)(), MyCustomWorker*> >::operator()() <null> (myApp+0x11de952)
#12 std::thread::_State_impl<std::thread::_Invoker<std::tuple<void (MyCustomWorker::*)(), MyCustomWorker*> > >::_M_run() <null> (myApp+0x11de524)
#13 execute_native_thread_routine <null> (liboatpp.so+0x3e4d3e)
这个堆栈有趣的部分不是数据竞争本身,而是调用堆栈的底部:
#13 execute_native_thread_routine <null> (liboatpp.so+0x3e4d3e)
二进制文件使用 oatpp 库,但发生竞争的代码与库完全无关。据我了解,这行说:
-
std::thread库的函数execute_native_thread_routine被liboatpp.so调用 -
MyCustomWorker运行的线程是由liboatpp.so代码创建的
因此,出于某种原因,我的二进制调用 std::thread 通过 liboatpp.so 运行,而不是我自己预期的那样。我已经(或考虑过)的:
- liboatpp 的符号列表,用于搜索在链接 MyApp 期间可能查找的任何“thread”相关符号。所有符号似乎都包含与 oatpp 相关的名称。
nm -gD liboatpp.so | grep thread | grep run的结果:
00000000003c7054 W _ZNSt6thread11_State_implINS_8_InvokerISt5tupleIJMN5oatpp3web6server13HttpProcessor4TaskEFvvES7_EEEEE6_M_runEv
...
(similar oatpp specific entries)
-
通过执行:
ltrace -l liboatpp.so ./MyApp | grep thread在liboatpp.so中搜索对线程相关函数的调用,但没有发现任何有趣的东西。我希望找到一些负责该问题的电话。 -
我还检查了导出
LD_DEBUG=all后动态链接器的输出,但也没有发现任何有趣的东西。在这里,我希望在 MyApp 中找到未解析的符号,以便在liboatpp.so中找到与线程相关的函数。没有观察到这样的事情。
已编辑:
libstdc++.a 绝对没有有意链接到 liboatpp.so。我确认它没有链接的证据是,如果我在 libstdc++.a (nm -g /opt/rh/devtoolset-8/root/usr/lib/gcc/x86_64-redhat-linux/8/libstdc++.a | grep thread) 中采用以下定义的符号之一:
0000000000000000 T _ZNSt6thread20hardware_concurrencyEv
0000000000000000 T _ZNSt6thread4joinEv
0000000000000000 T _ZNSt6thread6detachEv
然后在liboattp中搜索nm -gD liboatpp.so | grep thread:
U _ZNSt6thread6detachEv
但它被发现为未定义的符号。
Oatpp 链接命令如下:
c++ -fPIC -shared -Wl,-soname,liboatpp.so -o liboatpp.so CMakeFiles/oatpp.dir/oatpp/algorithm/CRC.cpp.o (...) -lpthread -latomic
【问题讨论】:
-
我不知道 liboatpp 是什么,但从堆栈跟踪看来,这个库确实创建了一个线程。为何如此令人惊讶?
-
这对我来说并不奇怪。 Oat++ 是一个“网络框架”,可能会创建线程。这并不出人意料。也许我错过了你的观点? (顺便说一句,Oat++ 网站似乎建议您将其构建为 static 库并链接到它:oatpp.io/docs/installation/unix-linux/…。)
-
@yzt 感谢您指出这一点,我一定会用适当的标志重建 Oat++。
-
你的“证据”证明了什么都没有。
libstdc++.a由许多.o文件组成,并且并非所有文件都最终包含在liboatpp.so中。显示您如何链接liboatpp.so可能是一个好的开始。 -
将
nm输出过滤为全局符号(-g标志)在这里会适得其反。
标签: c++ linux gcc linker dynamic-linking