Неопределенная ссылка на `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)
}
Другие вопросы по тегам