2

Есть объект std::thread, создающийся внутри функции. Создается так:

std::thread* th = new std::thread([](){код лямбды});

Однако указатель на объект пропадает после выхода из зоны видимости функции.

Вопрос, как освободить память, занятую std::thread, после его завершения?

P. S.: если заменить лямбду на пустую, программа падает уже на строке th->detach().

Arhadthedev
  • 11,528

2 Answers2

2

Как для любого динамического объекта - через delete. Только не забудьте сначала выполнить th->join() или th->detach()...

Harry
  • 221,325
  • Если бы я выполнял join(), проблем бы не было. Поток, запустивший th, не должен прерыватся или ждать выполнения th. –  Oct 07 '17 at 08:19
  • 2
    @Gravit, а вам точно надо создавать объект в куче? Может просто создать его в стэке и выполнить detach? – yrHeTateJlb Oct 07 '17 at 08:21
  • @yrHeTaTeJlb, попробывал сделать с стеком, получаю ошибку сегментирования –  Oct 07 '17 at 08:26
  • 1
    @Gravit, уточню: на стеке потока надо создавать данные этого потока. А так, если у вас ошибка сегментации, значит, вы некорректно с этими данными работаете (и перенос их в кучу попросту маскирует проблему). Вы никуда не передаёте указатели на локальные переменные лямбды? Приведите, пожалуйста, минимальный код, при котором воспроизводится падение. – Arhadthedev Oct 07 '17 at 08:43
  • Поток, запустивший th, не должен прерыватся или ждать выполнения th. - т.е. он больше не взаимодействует с th? Ну так вызывайте detach() и удаляйте указатель. А еще лучше - делайте это с локальной переменной, ничего удалять не придется... – Harry Oct 07 '17 at 08:48
  • @Gravit, «получаю ошибку сегментирования» прочитайте, что Вам yrHeTaTeJlb написал внимательнее. Особое внимание обратите на слово detach. – ixSci Oct 07 '17 at 09:40
  • @Arhad @Harry @ixSci, https://pastebin.com/gcsHS9UY код для воспроизведения проблемы. Скомлировать так: g++ test.cpp -lpthread -static. Без ключа -static выполняется все корректно. Крашит на вызове detach() –  Oct 07 '17 at 10:25
  • Вы захватываете локальную переменную по референсу. Поскольку это указатель на глобальную переменную - захватывайте ее по значению. Иначе переменая может выйти из области действия раньше, чем начнется поток. – Artemy Vysotsky Oct 07 '17 at 10:29
  • @ArtemyVysotsky падает даже при полном отсутствии кода внутри лямбды. Видимо я недостаточно точно написал действия в моей программе. Правильней было написать https://pastebin.com/Qphgp8g1 –  Oct 07 '17 at 10:36
  • @Harry, вообще, надо менять заголовок вопроса на «Статически скомпонованная программа падает при std::thread::detach», но есть проблема — уточнения пришли после вашего ответа. Ответ тоже удалить не получится — в комментариях к нему достаточно важная информация. Поднял дискуссию в чате. – Arhadthedev Oct 07 '17 at 11:52
  • @Arhad Ну извиняйте, кто ж знал :( – Harry Oct 07 '17 at 12:29
2

Подобное уже обсуждалось в системе отслеживания ошибок GCC. Как оказалось, это связано с тем, что libpthread не рассчитана на статическую компоновку:

При $ g++-4.7 -Wl,-M -v -static -pthread -std=c++0x -o thread thread.cc libpthread компонуется без проблем.

Проведя небольшое расследование, я выяснил, что /usr/include/c++/4.7.0/x86_64-linux-gnu/bits/gthr-posix.h объявляет всё как __attribute__((weakref)) даже при статической компоновке, из-за чего все символы __gthread_* обращаются в нулевые. Дополнительная информация может быть найдена по ссылке http://gcc.gnu.org/ml/gcc/2005-10/msg00235.html

Следующие флаги компиляции должны помочь:

$ g++ -D_GLIBCXX_GTHREAD_USE_WEAK=0 -static -pthread -std=c++0x -o thread thread.cc 
$ ./thread 
pthread_create works
std::thread works

Однако, если заменить join() на detach(), программа снова падает, на этот раз из-за нулевой ссылки на std::thread::detach:

Program received signal SIGSEGV, Segmentation fault.
0x0000000000000000 in ?? ()
(gdb) bt
#0  0x0000000000000000 in ?? ()
#1  0x0000000000439785 in std::thread::detach() ()
#2  0x0000000000401f52 in main ()

$ g++-4.7 -Wl,-M -v -static -pthread -std=c++0x -o thread thread.cc shows all of libpthread being linked.

With a bit more digging I traced the problem to /usr/include/c++/4.7.0/x86_64-linux-gnu/bits/gthr-posix.h declaring all of its symbols with __attribute__((weakref)) even when linking statically. Which caused the __gthread_* symbols to resolve to zero. I found this for some background info http://gcc.gnu.org/ml/gcc/2005-10/msg00235.html

This change made my example work:

$ g++ -D_GLIBCXX_GTHREAD_USE_WEAK=0 -static -pthread -std=c++0x -o thread thread.cc 
$ ./thread 
pthread_create works
std::thread works

However, if I change the code to call std::thread::detach instead of join, then it crashes again with std::thread::detach being resolved to zero.

Program received signal SIGSEGV, Segmentation fault.
0x0000000000000000 in ?? ()
(gdb) bt
#0  0x0000000000000000 in ?? ()
#1  0x0000000000439785 in std::thread::detach() ()
#2  0x0000000000401f52 in main ()

В связи с этим на англоязычном StackOverflow рекомендуют включить флаг компиляции -Wl,--whole-archive, либо перечислить все необходимые библиотеки вручную, узнав предварительно список зависимостей через nm.

А вообще:

Даже не думайте о статической компоновке. Разработчики glibc это не любят и не поддерживают. И однажды они начнут усложнять подобную практику с каждым релизом.


Do not even think about static linking. The glibc developers do not like it, they do not care about supporting it, and they somehow manage to break it a little harder with every release.

Arhadthedev
  • 11,528