I just came to Linux c++ programming from Windows. Trying to make a shared library libso.so, which uses std::thread
. The shared library will be loaded by other people and call the export function. The test code:
// so.cpp, the .so library
#include <iostream>
#include <thread>
using namespace std;
extern "C"
void run() {
cout << "run() begin" << endl;
std::thread t([] {
});
t.join();
cout << "run() end" << endl;
}
// test.cpp, the test loader
#include <dlfcn.h>
int main() {
typedef void (*run_t)();
auto dll = dlopen("libso.so", RTLD_LAZY);
run_t run = (run_t) dlsym(dll, "run");
run();
}
// The CMakeLists.txt file
cmake_minimum_required(VERSION 3.0)
PROJECT (test)
Include_Directories(${PROJECT_SOURCE_DIR})
Link_Directories(${PROJECT_BINARY_DIR})
add_library(so SHARED so.cpp )
target_link_libraries(so pthread)
add_executable( test test.cpp )
target_link_libraries(test pthread dl)
It crashes in the run()
function, the output is:
run() begin
“./test” terminated by signal SIGSEGV (Address boundary error)
The std::thread
seems work fine in executable, but not in shared library. What do I miss?
The environment: g++ 9.3.0, cmake 3.16.3
Edited:
Try ldd.
ldd ./test
shows no pthread
, but ldd ./libso.so
has libpthread.so.0
.
The difference of linking param with SET(CMAKE_VERBOSE_MAKEFILE TRUE)
// linking executable 'test'
/usr/bin/c++ -rdynamic CMakeFiles/test.dir/test.cpp.o -o test -L/e/c/1/kali -Wl,-rpath,/e/c/1/kali -ldl -lpthread
// linking library 'libso.so'
/usr/bin/c++ -fPIC -shared -Wl,-soname,libso.so -o libso.so CMakeFiles/so.dir/so.cpp.o -L/e/c/2/kali -Wl,-rpath,/e/c/1/kali -lpthread
The only difference is -fPIC
, I googled and add set_property(TARGET test PROPERTY POSITION_INDEPENDENT_CODE ON)
to the executable, but nothing changed.
Workaround 1
Since the .so has libpthread.so.0
, I tried to add the code in .so to the executable:
int main() {
std::thread t([]{}); // to make executable linking to `pthread`
t.join();
// ... load dll and call run function
}
And it works, now the ldd ./test
shows libpthread.so.0
and no crash. Which means: if a shared library uses std::thread
and an executable wants to load it, the executable itself must also use std::thread
.
Workaround 2:
The std::thread
works fine in executable, but crashes in shared library. Found some related discuss, the walkaround is using boost::thread
instead of std::thread
and linking to boost_thread
library, no crash .