Что происходит с отсоединенным потоком при выходе main ()?



предположим, что я начинаю std::thread а то detach() это, так что поток продолжает выполняться, даже если std::thread то, что когда-то представляло его, выходит за рамки.



предположим далее, что программа не имеет надежного протокола для вступления в отдельной теме1, поэтому отсоединенный поток все еще работает, когда main() выход.



Я не могу найти ничего в стандарте (точнее, в проекте N3797 C++14), который описывает, что должно произойти, ни 1.10, ни 30.3 не содержат соответствующей формулировки.



1 другой, вероятно эквивалентный, вопрос: "Может ли отсоединенный поток когда-либо быть присоединен снова", потому что независимо от того, какой протокол вы изобретаете для присоединения, сигнальная часть должна быть выполнена, пока поток все еще работает, и планировщик ОС может решить перевести поток в спящий режим на час сразу после того, как сигнализация была выполнена без возможности для приемного конца надежно обнаружить, что поток на самом деле законченный.



если main() С отсоединенными потоками работает неопределенное поведение, то любой использование std::thread::detach() неопределенное поведение, если основной поток никогда не выходит2.



таким образом, заканчивается main() С отсоединенными потоками работает должен иметь определена эффекты. Вопрос в том:здесьстандарт C++, не POSIX, не OS docs,...) эти эффекты определенный.



2 отсоединенный поток не может быть соединен (в смысле std::thread::join()). Ты можете дождитесь результатов от отсоединенных потоков (например, через будущее от std::packaged_task, или с помощью Счетного семафора или флага и переменной условия), но это не гарантирует, что поток завершил выполнение. Действительно, если вы не поместите сигнальную часть в деструктор первого автоматического объекта потока, там будет, in генерал, будьте код (деструкторы), которые работают после код сигнализации. Если ОС планирует основной поток для использования результата и выхода до того, как отсоединенный поток завершит выполнение указанных деструкторов, что будет^WIS определено?

811   5  

5 ответов:

ответ на исходный вопрос "что происходит с отдельной нитью, когда main() выход" является:

он продолжает работать (потому что стандарт не говорит, что он остановлен), и это четко определено, пока он не касается ни (автоматических|thread_local) переменных других потоков, ни статических объектов.

это, кажется, разрешено разрешить менеджерам потоков как статические объекты (примечание в [basic.начать.срок]/4 говорит столько же, спасибо @dyp за указатель.)

проблемы возникают, когда уничтожение статических объектов завершено, потому что тогда выполнение переходит в режим, в котором может выполняться только код, разрешенный в обработчиках сигналов ([basic.начать.термин] / 1, 1-е предложение). Из стандартной библиотеки C++ это только <atomic> библиотека ([поддержку.runtime] / 9, 2-е предложение). В частности, что-вообще -исключитьcondition_variable (это реализация-определяется ли это сохранить для использования в a обработчик сигналов, потому что это не часть <atomic>).

если вы не размотали свой стек в этот момент, трудно понять, как избежать неопределенного поведения.

ответ на второй вопрос "Могут ли отсоединенные потоки когда-либо быть соединены снова":

да, с *_at_thread_exit семейство функций (notify_all_at_thread_exit(),std::promise::set_value_at_thread_exit(), ...).

как отмечено в сноске [2] вопроса, сигнализация переменной условия или семафора или атомарного счетчика не является достаточно присоединить отсоединенный поток (в смысле обеспечения того, что конец его выполнения уже было-перед получение указанной сигнализации ожидающим потоком), потому что, как правило, будет выполняться больше кода, например, после a notify_all() переменной условия, в частности деструкторов автоматических и потоковых локальных объектов.

запуск сигнализации как последнее, что делает поток (после деструкторы автоматических и локальных объекты уже было) то _at_thread_exit семейство функций было разработано для.

Итак, чтобы избежать неопределенного поведения при отсутствии каких-либо гарантий реализации выше того, что требует стандарт, вам нужно (вручную) присоединиться к отдельному потоку с _at_thread_exit функция делает сигнализацию или сделать отдельный поток выполнения только код, который был бы безопасен для обработчика сигнала, тоже.

Отсоединение Нитей

по данным std::thread::detach:

отделяет поток выполнения от объекта потока, позволяя выполнение продолжить самостоятельно. Любые выделенные ресурсы будут освобождается после выхода потока.

С pthread_detach:

функция pthread_detach() должна указывать на реализацию это хранилище для потока может быть восстановлено когда эта нить прекращает. Если поток не был прерван, pthread_detach() не должен заставьте его прерваться. Эффект нескольких вызовов pthread_detach() в том же целевом потоке не указано.

отсоединение потоков в основном предназначено для экономии ресурсов, если приложению не нужно ждать завершения потока (например, демоны, которые должны выполняться до завершения процесса):

  1. освободить ручку стороны применения: можно позволить а std::thread объект выходит из области видимости без присоединения, что обычно приводит к вызову std::terminate() на уничтожение.
  2. чтобы ОС могла очищать определенные ресурсы потока (TCB) автоматически, как только поток выходит, потому что мы явно указали, что мы не заинтересованы в присоединении к потоку позже, таким образом, нельзя присоединиться к уже отсоединенному потоку.

Убивать Темы

в поведение при завершении процесса такое же, как и для основного потока, который мог бы, по крайней мере, поймать некоторые сигналы. Независимо от того, могут ли другие потоки обрабатывать сигналы, это не так важно, поскольку можно объединить или завершить другие потоки в вызове обработчика сигналов основного потока. (вопрос)

как уже было сказано, любая нить, независимо от того, отсоединена она или нет, умрет вместе со своим процессом на большинстве ОС. Сам процесс может быть прекращен поднимая сигнал, вызывая exit() или по возвращении из функции main. Однако C++11 не может и не пытается определить точное поведение базовой ОС, в то время как разработчики виртуальной машины Java могут в некоторой степени абстрагировать такие различия. AFAIK, экзотические модели процессов и потоков обычно встречаются на древних платформах (на которые C++11, вероятно, не будет перенесен) и различных встроенных системах, которые могут иметь специальную и/или ограниченную реализацию библиотеки языков, а также ограниченная языковая поддержка.

Нить

если потоки не поддерживаются std::thread::get_id() должен вернуть недопустимый идентификатор (по умолчанию построен std::thread::id) так как есть простой процесс, которому не нужен объект потока для запуска и конструктор a std::thread должны бросить std::system_error. Вот как я понимаю C++11 в сочетании с сегодняшними ОС. Если есть ОС с поддержкой потоков, которая не порождает основной поток в своих процессах, дайте мне знать.

Управляя Потоками

если нужно сохранить контроль над потоком для правильного завершения работы, можно сделать это с помощью примитивов синхронизации и/или каких-то флагов. Однако в этом случае установка флага завершения работы с последующим соединением-это то, что я предпочитаю, поскольку нет смысла увеличивать сложность путем отсоединения потоков, так как ресурсы будут освобождены одновременно в любом случае, где несколько байтов std::thread объект против более высокой сложности и, возможно, больше примитивов синхронизации должны быть приемлемыми.

судьба нить после того, как программа завершает свою работу-это неопределенное поведение. но современная операционная система очистит все потоки, созданные процессом при его закрытии.

при отсоединенииstd::thread эти три условия будут продолжать держать

  1. *this больше не владеет ни одной нитью
  2. joinable() всегда будет равно false
  3. get_id () будет равен std:: thread:: id ()

рассмотрим следующий код:

#include <iostream>
#include <string>
#include <thread>
#include <chrono>

void thread_fn() {
  std::this_thread::sleep_for (std::chrono::seconds(1)); 
  std::cout << "Inside thread function\n";   
}

int main()
{
    std::thread t1(thread_fn);
    t1.detach();

    return 0; 
}

запуск его в системе Linux, сообщение от thread_fn никогда не печатается. ОС действительно очищает thread_fn() Как только main() выход. Замена t1.detach() С t1.join() всегда печатает сообщение, как ожидалось.

когда основной поток (то есть поток, который выполняет функцию main ()) завершается, то процесс завершается и все остальные потоки останавливаются.

Ссылка:https://stackoverflow.com/a/4667273/2194843

Comments

    Ничего не найдено.