Недавно я обнаружил странное поведение, используя std::thread
и dlopen
.
В основном, когда я выполняю std::thread
в библиотеке, которая загружается с помощью dlopen
, я получаю сигсев.Сама библиотека связана с pthread, исполняемый файл, который вызывает dlopen
, не является.
Как только я связываю исполняемый файл с pthread
или с самой библиотекой, все работает нормально.Однако мы используем инфраструктуру на основе плагинов, где мы не знаем, связано ли само приложение с pthread или нет.Поэтому нельзя всегда связывать исполняемый файл с pthread.
Пожалуйста, найдите прикрепленный код, чтобы воспроизвести проблему.В настоящее время я не уверен, что является причиной проблемы.Это проблема gcc, glibc, libstdc ++ или ld.so?Есть ли удобный способ обойти это?Похоже, что ошибка glibc связана, но я использую glibc2.27 (тестирование Debian).
Кажется, что сам вызов pthread_create
из библиотеки работает.
hello.cpp
#include <thread>
#include <iostream>
void thread()
{
std::thread t ([](){std::cout << "hello world" << std::endl;});
t.join();
}
extern "C" {
void hello()
{
thread();
}
}
example.cpp
#include <iostream>
#include <dlfcn.h>
/** code from https://www.tldp.org/HOWTO/html_single/C++-dlopen/
*/
int main() {
std::cout << "C++ dlopen demo\n\n";
// open the library
std::cout << "Opening hello.so...\n";
void* handle = dlopen("./libhello.so", RTLD_LAZY);
if (!handle) {
std::cerr << "Cannot open library: " << dlerror() << '\n';
return 1;
}
// load the symbol
std::cout << "Loading symbol hello...\n";
typedef void (*hello_t)();
// reset errors
dlerror();
hello_t hello = (hello_t) dlsym(handle, "hello");
const char *dlsym_error = dlerror();
if (dlsym_error) {
std::cerr << "Cannot load symbol 'hello': " << dlsym_error <<
'\n';
dlclose(handle);
return 1;
}
// use it to do the calculation
std::cout << "Calling hello...\n";
hello();
// close the library
std::cout << "Closing library...\n";
dlclose(handle);
}
build.sh (сборка и выполнение верхнего примера. Сбой примера 1)
#!/bin/bash
echo "g++ -shared -fPIC -std=c++14 hello.cpp -o libhello.so -pthread"
g++ -shared -fPIC -std=c++14 hello.cpp -o libhello.so -pthread
echo "g++ example.cpp -o example1 -ldl"
g++ example.cpp -o example1 -ldl
echo "g++ example.cpp -o example2 -ldl -pthread"
g++ example.cpp -o example2 -ldl -pthread
echo "g++ example.cpp -o example3 -ldl -lhello -L ./"
g++ example.cpp -o example3 -ldl -lhello -L ./
export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:$(pwd)
echo "===== example1 ====="
./example1
echo "===== end ====="
echo "===== example2 ====="
./example2
echo "===== end ====="
echo "===== example3 ====="
./example3
echo "===== end ====="
EDIT
Я забыл упомянуть: если я запускаю ошибочный пример (например, пример 1) с использованием LD_DEBUG=all
, программа вылетает при поиске pthread_create
.Еще интереснее то, что прежний поиск pthread_create
завершается успешно:
8111: symbol=_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_; lookup in file=/usr/lib/x86_64-linux-gnu/libstdc++.so.6 [0]
8111: binding file ./libhello.so [0] to /usr/lib/x86_64-linux-gnu/libstdc++.so.6 [0]: normal symbol `_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_' [GLIBCXX_3.4]
8111: symbol=pthread_create; lookup in file=./example1 [0]
8111: symbol=pthread_create; lookup in file=/lib/x86_64-linux-gnu/libdl.so.2 [0]
8111: symbol=pthread_create; lookup in file=/usr/lib/x86_64-linux-gnu/libstdc++.so.6 [0]
8111: symbol=pthread_create; lookup in file=/lib/x86_64-linux-gnu/libm.so.6 [0]
8111: symbol=pthread_create; lookup in file=/lib/x86_64-linux-gnu/libgcc_s.so.1 [0]
8111: symbol=pthread_create; lookup in file=/lib/x86_64-linux-gnu/libc.so.6 [0]
8111: symbol=pthread_create; lookup in file=/lib64/ld-linux-x86-64.so.2 [0]
8111: symbol=pthread_create; lookup in file=./libhello.so [0]
8111: symbol=pthread_create; lookup in file=/usr/lib/x86_64-linux-gnu/libstdc++.so.6 [0]
8111: symbol=pthread_create; lookup in file=/lib/x86_64-linux-gnu/libm.so.6 [0]
8111: symbol=pthread_create; lookup in file=/lib/x86_64-linux-gnu/libgcc_s.so.1 [0]
8111: symbol=pthread_create; lookup in file=/lib/x86_64-linux-gnu/libpthread.so.0 [0]
8111: binding file ./libhello.so [0] to /lib/x86_64-linux-gnu/libpthread.so.0 [0]: normal symbol `pthread_create' [GLIBC_2.2.5]
8111: symbol=_ZTVNSt6thread6_StateE; lookup in file=./example1 [0]
8111: symbol=_ZTVNSt6thread6_StateE; lookup in file=/lib/x86_64-linux-gnu/libdl.so.2 [0]
8111: symbol=_ZTVNSt6thread6_StateE; lookup in file=/usr/lib/x86_64-linux-gnu/libstdc++.so.6 [0]
8111: binding file ./libhello.so [0] to /usr/lib/x86_64-linux-gnu/libstdc++.so.6 [0]: normal symbol `_ZTVNSt6thread6_StateE' [GLIBCXX_3.4.22]
...
8111: binding file ./libhello.so [0] to ./libhello.so [0]: normal symbol `_ZNSt10_Head_baseILm0EPNSt6thread6_StateELb0EE7_M_headERS3_'
8111: symbol=_ZNSt6thread15_M_start_threadESt10unique_ptrINS_6_StateESt14default_deleteIS1_EEPFvvE; lookup in file=./example1 [0]
8111: symbol=_ZNSt6thread15_M_start_threadESt10unique_ptrINS_6_StateESt14default_deleteIS1_EEPFvvE; lookup in file=/lib/x86_64-linux-gnu/libdl.so.2 [0]
8111: symbol=_ZNSt6thread15_M_start_threadESt10unique_ptrINS_6_StateESt14default_deleteIS1_EEPFvvE; lookup in file=/usr/lib/x86_64-linux-gnu/libstdc++.so.6 [0]
8111: binding file ./libhello.so [0] to /usr/lib/x86_64-linux-gnu/libstdc++.so.6 [0]: normal symbol `_ZNSt6thread15_M_start_threadESt10unique_ptrINS_6_StateESt14default_deleteIS1_EEPFvvE' [GLIBCXX_3.4.22]
8111: symbol=pthread_create; lookup in file=./example1 [0]
8111: symbol=pthread_create; lookup in file=/lib/x86_64-linux-gnu/libdl.so.2 [0]
8111: symbol=pthread_create; lookup in file=/usr/lib/x86_64-linux-gnu/libstdc++.so.6 [0]
8111: symbol=pthread_create; lookup in file=/lib/x86_64-linux-gnu/libm.so.6 [0]
8111: symbol=pthread_create; lookup in file=/lib/x86_64-linux-gnu/libgcc_s.so.1 [0]
8111: symbol=pthread_create; lookup in file=/lib/x86_64-linux-gnu/libc.so.6 [0]
8111: symbol=pthread_create; lookup in file=/lib64/ld-linux-x86-64.so.2 [0]
./build.sh: line 18: 8111 Segmentation fault (core dumped) LD_DEBUG=all ./example1
===== end =====