С++ 0x проблема статического связывания потока

У меня возникают проблемы с попыткой статической привязки программ с использованием функций потока С++ 0x. Код выглядит так: (Компилятор является gcc 4.6.1 при тестировании Debian x86_64)

#include <iostream>
#include <thread>

static void foo() {
  std::cout << "FOO BAR\n";
}

int main() {
  std::thread t(foo);
  t.join();
  return 0;
}

Я связываю его с:

g++ -static -pthread -o t-static t.cpp -std=c++0x

Когда я запускаю программу, у меня есть следующая ошибка:

terminate called after throwing an instance of 'std::system_error'
  what(): Operation not permitted
Aborted

Результат отладки GDB выглядит следующим образом:

Debugger finished
Current directory is ~/testspace/thread/
GNU gdb (GDB) 7.2-debian
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/will/testspace/thread/t-static...done.
(gdb) list -
1   #include <iostream>
(gdb) b 1
Breakpoint 1 at 0x4007c8: file t.cpp, line 1.
(gdb) r
Starting program: /home/will/testspace/thread/t-static 
terminate called after throwing an instance of 'std::system_error'
  what():  Operation not permitted

Program received signal SIGABRT, Aborted.
0x00000000004a8e65 in raise ()
(gdb) bt
#0  0x00000000004a8e65 in raise ()
#1  0x000000000045df90 in abort ()
#2  0x000000000044570d in __gnu_cxx::__verbose_terminate_handler() ()
#3  0x0000000000442fb6 in __cxxabiv1::__terminate(void (*)()) ()
#4  0x0000000000442fe3 in std::terminate() ()
#5  0x0000000000443cbe in __cxa_throw ()
#6  0x0000000000401fe4 in std::__throw_system_error(int) ()
#7  0x00000000004057e7 in std::thread::_M_start_thread(std::shared_ptr<std::thread::_Impl_base>) ()
#8  0x0000000000400b18 in std::thread::thread<void (&)()> (this=0x7fffffffe540, [email protected]) at /usr/include/c++/4.6/thread:135
#9  0x00000000004007f3 in main () at t.cpp:11
(gdb)

Update:

Связывание со статическим libstdС++ могло (возможно) сделать эту ошибку, и скомпилированные С++ 0x-программы могут запускаться в системах без gcc 4.6 libs:

g++ -static-libgcc -pthread -L.-o t thread.cpp -std=c++0x

Но сначала мы должны сделать символическую ссылку на "libstdС++. a" в текущем каталоге:

ln -s `g++ -print-file-name=libstdc++.a`

(Ссылка: http://www.trilithium.com/johan/2005/06/static-libstdc/)

Ответ 1

По причинам, которые мне точно неизвестны (я считаю это ошибкой), вы не можете использовать std:: thread on gcc 4.6 при связывании статически, так как функция __ghtread_active_p() будет включена в качестве возвращаемого значения false (посмотрите на сборку _M_start_thread), вызывая это исключение. Возможно, они нуждаются в слабых символах для функции pthread_create и при статической привязке их там нет, но почему они этого не делают, иначе это вне меня (обратите внимание, что сборка позже содержит такие вещи, как callq 0x0, похоже, что-то очень не так).

В настоящее время я лично использую boost:: threads, так как я использую boost anyways...

Ответ 2

Вы должны убедиться, что вы связываетесь с библиотекой pthread, иначе вы получите сообщение "Операция не разрешена".

Например, чтобы скомпилировать исходный код, я бы использовал следующее:

g++ -Wall -fexceptions  -std=c++0x -g -c file.cpp -o file.o

Затем, связываясь с этим:

g++ -o file file.o -lpthread

Когда вы делаете это без объектных файлов, вы можете попробовать что-то вроде этого:

g++ -Wall -fexceptions -std=c++0x -g main.cpp -o file -lpthread

Не забудьте оставить библиотеки в конце, так как они будут использоваться только для процесса компоновки.

Ответ 3

вы можете использовать -u для решения проблемы (тест в gcc версии 4.6.3/(Ubuntu EGLIBC 2.15-0ubuntu10.4) 2.15, gcc версия 4.8.1/(Ubuntu EGLIBC 2.15-0ubuntu10.5 ~ ppa1) 2.15 )

-Wl, -u, pthread_cancel, -u, pthread_cond_broadcast, -u, pthread_cond_destroy, -u, pthread_cond_signal, -u, pthread_cond_wait, -u, pthread_create, -u, pthread_detach, -u, pthread_cond_signal, - и, pthread_equal, -u, pthread_join, -u, pthread_mutex_lock, -u, pthread_mutex_unlock, -u, pthread_once, -u, pthread_setcancelstate

1. воспроизведите ошибку

g++ -g -O0 -static -std=c++11 t.cpp -lpthread
./a.out
terminate called after throwing an instance of 'std::system_error'
  what():  Enable multithreading to use std::thread: Operation not permitted
Aborted (core dumped)


nm a.out | egrep "\bpthread_.*"
                 w pthread_cond_broadcast
                 w pthread_cond_destroy
                 w pthread_cond_signal
                 w pthread_cond_wait
                 w pthread_create
                 w pthread_detach
                 w pthread_equal
                 w pthread_join
                 w pthread_mutex_lock
                 w pthread_mutex_unlock
                 w pthread_once
                 w pthread_setcancelstate

2. разрешить ошибку

g++ -g -O0 -static -std=c++11 t.cpp -lpthread -Wl,-u,pthread_join,-u,pthread_equal
./a.out  
FOO BAR  


nm a.out | egrep "\bpthread_.*"  
0000000000406320 T pthread_cancel
                 w pthread_cond_broadcast
                 w pthread_cond_destroy
                 w pthread_cond_signal
                 w pthread_cond_wait
0000000000404970 W pthread_create
                 w pthread_detach
00000000004033e0 T pthread_equal
00000000004061a0 T pthread_getspecific
0000000000403270 T pthread_join
0000000000406100 T pthread_key_create
0000000000406160 T pthread_key_delete
00000000004057b0 T pthread_mutex_lock
00000000004059c0 T pthread_mutex_trylock
0000000000406020 T pthread_mutex_unlock
00000000004063b0 T pthread_once
                 w pthread_setcancelstate
0000000000406220 T pthread_setspecific

Ответ 4

Мой предыдущий ответ был удален, и я написал подробный ответ.

В обычных случаях эта проблема возникает из-за неполной связи libpthread. Я нашел информацию об этом здесь https://gcc.gnu.org/bugzilla/show_bug.cgi?id=52590

Вы можете попробовать связать свое приложение со следующими флагами:

-Wl,--whole-archive -lpthread -Wl,--no-whole-archive

Также вы можете посмотреть на эти вопросы с аналогичной проблемой: Каковы правильные параметры ссылок для использования std:: thread в GCC под linux? Запуск std:: thread со статической связью вызывает ошибку сегментации