Неопределенная ссылка на `pthread_create'Ошибка при создании приложения C++11 с ASIO и std::thread
Я установил Eclipse (на самом деле Xilinx SDK, но основан на Eclipse) и g++4.9.2 для компиляции проекта, который использует автономный ASIO, и я использовал -std= C++11 в Свойствах -> C/C++ Build -> Настройки -> Настройки инструмента -> Другие флаги, чтобы он мог компилироваться с использованием всех функций C++11.
Я тоже поставил ASIO_HAS_STD_THREAD, ASIO_STANDALONE
и так далее в C / C++ Общие символы, и я ожидаю, что заголовок ASIO будет использовать std::thread
вместо pthread
, Тем не менее, я все еще вижу ошибку от make:
undefined reference to pthread_create,
..asio-1.10.6\include\asio\detail\impl\posix_thread.ipp
and posix_tss_ptr.hpp
так что проблема в том, что я использую C++11 и указал ASIO_HAS_STD_THREAD
но нет ASIO_HAS_PTHREADS
, posix_thread.ipp
не должен даже быть включен (через posix_thread.hpp), согласно thread.hpp в ASIO:
#if !defined(ASIO_HAS_THREADS)
# include "asio/detail/null_thread.hpp"
#elif defined(ASIO_WINDOWS)
# if defined(UNDER_CE)
# include "asio/detail/wince_thread.hpp"
# else
# include "asio/detail/win_thread.hpp"
# endif
#elif defined(ASIO_HAS_PTHREADS)
# include "asio/detail/posix_thread.hpp"
#elif defined(ASIO_HAS_STD_THREAD)
# include "asio/detail/std_thread.hpp"
#else
# error Only Windows, POSIX and std::thread are supported!
#endif
Подозреваемый 1-нитка
Вопреки мнению большинства людей, C++11 не нуждается в -pthread
и я попытался скомпилировать простой проект без -pthread
в затмении. Тем не менее, вы можете исправить меня, если я ошибаюсь. Когда я положил -pthread
в компоновщике он компилируется, однако я чувствовал, что не хочу pthread, если в этом нет необходимости.
Подозреваемый 2 - ASIO makefile
Когда я ищу в posix_tss_ptr.hpp, я обнаружил также в Makefile.am. Интересно, повлияет ли это на ошибку?
Так в чем же причина проблемы? Если не два вышеупомянутых подозреваемых? Я надеюсь, что решение все еще может быть на чистом C++11, а не на pthread, если мои рассуждения верны.
Обновить
Я обнаружил, что ASIO_HAS_PTHREADS определяется не мной, и поэтому ASIO где-то использует потоки POSIX, а компоновщику тогда нужна опция -pthread. Затем я проследил путь к asio/detail/signal_blocker.hpp с помощью директивы #error. Есть только два места, которые он определил, и они находятся в ASIO config.hpp
# if defined(ASIO_HAS_BOOST_CONFIG) && defined(BOOST_HAS_PTHREADS)
# define ASIO_HAS_PTHREADS 1
# elif defined(_POSIX_THREADS)
# define ASIO_HAS_PTHREADS 1
ASIO по-прежнему отвечает на POSIX THREADS или Windows для signal_blocker.hpp, показанного ниже. Вот почему ASIO все еще нуждается в pthread.
#if !defined(ASIO_HAS_THREADS) || defined(ASIO_WINDOWS) \
|| defined(ASIO_WINDOWS_RUNTIME) \
|| defined(__CYGWIN__) || defined(__SYMBIAN32__)
typedef null_signal_blocker signal_blocker;
#elif defined(ASIO_HAS_PTHREADS)
typedef posix_signal_blocker signal_blocker;
#endif
И _PTHREADS определяется из кросс-компилятора gnu (arm-xilinx-linux-gnueabi), включая файлы, такие как features.h, posix_opt.h и т. Д. Я не собираюсь отслеживать, кто действительно определил макрос, но ASIO - это источник, который использует _POSIX_THREADS и поэтому опция компоновщика -pthread должна быть там.
Опять же, не ASIO C++11 поток не нуждается в -pthread для g++4.9.2, но автономный ASIO нуждается в этом. Следующий код построен правильно без -pthread в g++4.9.2 (Xilinx SDK, основанный на Eclipse):
#include <thread>
void test() {
for(int i=0;i<100;i++);
}
int main()
{
std::thread thread1(test);
thread1.join();
return 0;
}
3 ответа
Тот факт, что программа написана на C++11, не имеет отношения к тому, должна ли она быть связана с pthread
библиотека. Нужно связать эту библиотеку, если ей нужны потоки Posix.
C++11 обеспечивает std::thread
Класс и стандартная библиотека каждого соответствующего компилятора должны реализовывать функциональные возможности этого класса с использованием некоторого API собственных потоков, размещенного в целевой системе. GCC реализует это используя pthreads
Таким образом, вы не можете построить программу, которая создает std::thread
объекты с GCC, если вы не связываете его с -pthread
, Этот факт не связан с asio
,
ПОТОМ
Я на самом деле собрал программу без pthread, используя std::std, просто используя -std= C++11
Я думаю, что вы ошибаетесь и смущены тем, что некоторые порты Windows GCC связывают libpthread
по умолчанию. Например, если ваш пример программы находится в thread.cpp
Я могу успешно построить его в Windows с TDM-GCC 4.9.2 так:
>g++ -std=c++11 -o test_thread thread.cpp
Но если вы построите его в подробном режиме:
>g++ -v -std=c++11 -o test_thread thread.cpp
вы можете видеть, что очень много опций библиотеки передаются компоновщику за кулисы, в частности -lpthread
:
>g++ -v -std=c++11 -o test_thread thread.cpp 2>&1 | grep -Po 'pass-through=-lpthread' -
pass-through=-lpthread
А на линукс не будешь ссылаться libpthread
если вы не спросите:
$ g++ -std=c++11 -o test_thread thread.cpp
/tmp/ccpyEles.o: In function `std::thread::thread<void (&)()>(void (&)())':
thread.cpp:(.text._ZNSt6threadC2IRFvvEJEEEOT_DpOT0_[_ZNSt6threadC5IRFvvEJEEEOT_DpOT0_]+0x7d): undefined reference to `pthread_create'
collect2: error: ld returned 1 exit status
Во время выполнения кода используйте g++ ssss(ваше кодовое имя).cpp -std= C++11 -pthread
это будет работать
1. std::thread не нуждается в -pthread
Вот что я выкопал из ASIO, и позвольте мне сначала показать простой пример. В 32-разрядной версии CentOS 6.5 и в Eclipse с использованием g++4.9.3 следующий код создается только с -std= C++11, не нужно указывать -lpthread
std::string make_greeting_string()
{
auto now = std::chrono::system_clock::now();
const auto in_time_t = std::chrono::system_clock::to_time_t(now);
std::stringstream ss;
//ss << std::put_time(std::localtime(&in_time_t), "%Y-%m-%d %X");
ss << "Greetings"<<45;
return ss.str();
}
int main() {
std::thread thread1(make_greeting_string);
//test2();
thread1.join();
cout << "!!!Hello World!!!" << endl; // prints !!!Hello World!!!
return 0;
}
Как только я добавляю tes2() в main, происходит сбой с неопределенной ссылкой на `pthread_create '
void *PrintHello(void *threadid)
{
long tid;
tid = (long)threadid;
std::cout<<"Hello World! It's me, thread #%ld!"<<tid<<std::endl;
pthread_exit(NULL);
}
void test2()
{
pthread_t threads[NUM_THREADS];
int rc;
long t;
for(t=0;t<NUM_THREADS;t++){
std::cout<<"In main: creating thread %ld"<<t<<std::endl;
rc = pthread_create(&threads[t], NULL, PrintHello, (void *)t);
if (rc){
std::cout<<"ERROR; return code from pthread_create() is "<<rc<<std::endl;
exit(-1);
}
}
}
2. Источник зависимости ASIO от -pthread
Во-первых, в автономном ASIO есть код, который использует поток posix, но также может использовать std. Порядок должен быть переставлен так, чтобы сначала использовать std, когда оба определены. Пример кода из строки static_mutex.hpp 27
#elif defined(ASIO_HAS_PTHREADS)
#include "asio/detail/posix_static_mutex.hpp"
#elif defined(ASIO_HAS_STD_MUTEX_AND_CONDVAR)
#include "asio/detail/std_static_mutex.hpp"
Во-вторых, есть еще два файла, которые нуждаются в posix: signal_blocker.hpp и tss_ptr.hpp. Make потерпит неудачу, потому что поддерживаются только Windows и POSIX
Я не знаю, возможно ли полностью переписать два файла для использования C++11, но эти два файла являются источником зависимости от -lpthread, а не от std::thread.
Обновить
tss_ptr.hpp
утверждает, что если ASIO_HAS_THREAD_KEYWORD_EXTENSION
определяется, это не нуждается в pthread. После того как я определил это в символах, ошибки make упали вдвое, указывая только на signal_blocker.hpp
является источником этой зависимости.
влияет на signal_set_service.ipp
case asio::io_service::fork_child:
if (state->fork_prepared_)
{
asio::detail::signal_blocker blocker;
close_descriptors();
open_descriptors();
int read_descriptor = state->read_descriptor_;
state->fork_prepared_ = false;
lock.unlock();
reactor_.register_internal_descriptor(reactor::read_op,
read_descriptor, reactor_data_, new pipe_read_op);
}
break;
и select_reactor.ipp
{
#if defined(ASIO_HAS_IOCP)
asio::detail::signal_blocker sb;
thread_ = new asio::detail::thread(
bind_handler(&select_reactor::call_run_thread, this));
#endif // defined(ASIO_HAS_IOCP)
}