Ответ 1
- Предопределять ресурсы и позже запускать поток почти сразу.
- У вас есть механизм, который повторно использует поток (возобновляет его), но у вас нет потока для повторного использования, и вы должны его создать.
API-интерфейсы потоков Windows и Solaris позволяют создавать поток в "приостановленном" состоянии. Поток начинается только тогда, когда он "возобновляется". Я привык к потокам POSIX, которые не имеют этой концепции, и я изо всех сил пытаюсь понять ее мотивацию. Может ли кто-нибудь предположить, почему было бы полезно создать "приостановленный" поток?
Вот простой иллюстративный пример. WinAPI позволяет мне это сделать:
t = CreateThread(NULL,0,func,NULL,CREATE_SUSPENDED,NULL);
// A. Thread not running, so do... something here?
ResumeThread(t);
// B. Thread running, so do something else.
По сравнению с эквивалентом POSIX (более простой):
// A. Thread not running, so do... something here?
pthread_create(&t,NULL,func,NULL);
// B. Thread running, so do something else.
Есть ли у кого-нибудь реальные примеры, где они могли что-то сделать в точке A (между CreateThread и ResumeThread), что было бы сложно в POSIX?
Может быть полезно создать поток во взвешенном состоянии во многих случаях (я нахожу) - вы можете захотеть получить дескриптор потока и установить некоторые его свойства, прежде чем разрешить ему использовать ресурсы, которые вы используете настройка для него.
Запуск приостановлен намного безопаснее, чем запуск, а затем приостановить его - вы не представляете, как далеко он добрался или что он делает.
Другой пример может быть, когда вы хотите использовать пул потоков - вы создаете необходимые потоки спереди, приостанавливаете, а затем, когда приходит запрос, выбирайте один из потоков, задаете информацию о потоке для задачи и затем установите его как планируемое.
Я смею сказать, что есть способы обойти, не имея CREATE_SUSPENDED, но он, безусловно, имеет свои возможности.
Есть несколько примеров использования в Windows с помощью C/С++ (Richter/Nasarre), если вы хотите много деталей!
Возможно, вы захотите запустить поток с каким-либо другим (обычно более низким) приоритетом или с определенной маской сродства. Если вы создадите его как обычно, он может работать с нежелательным приоритетом/сродством в течение некоторого времени. Итак, вы запустите его, измените нужные параметры, затем возобновите поток.
В CreateThread существует неявное состояние гонки: вы не можете получить идентификатор потока до тех пор, пока поток не начнет работать. Это совершенно непредсказуемо, когда вызов возвращается, поскольку вы знаете, что поток уже завершен. Если поток вызывает какое-либо взаимодействие в остальной части этого процесса, для которого требуется TID, тогда у вас есть проблема.
Это не неразрешимая проблема, если API не поддерживает запуск приостановленного потока, просто сразу же отредактируйте блок потока на мьютексе и отпустите этот мьютекс после возврата вызова CreateThread.
Однако, существует другое использование для CREATE_SUSPENDED в Windows API, с которым очень сложно справиться, если поддержка API отсутствует. Вызов CreateProcess() также принимает этот флаг, он приостанавливает поток запуска процесса. Механизм идентичен, процесс загружается, и вы получите PID, но код не запускается до тех пор, пока вы не отпустите начальный поток. Это очень полезно, я использовал эту функцию для настройки защиты процесса, которая обнаруживает сбой процесса и создает мини-накопитель. Флаг CREATE_SUSPEND позволил мне обнаружить и справиться с ошибками инициализации, как правило, очень сложно устранить неполадки.
Потоки, которые мы используем, могут обмениваться сообщениями, и у нас есть произвольно конфигурируемые очереди с приоритетом сообщений (описанные в файле конфигурации), которые соединяют эти потоки. До тех пор, пока каждая очередь не будет построена и не будет подключена к каждому потоку, мы не сможем разрешить выполнение потоков, так как они начнут отправлять сообщения в никуда и ожидать ответов. До тех пор, пока не будет построен каждый поток, мы не сможем создать очереди, так как им нужно что-то придать. Таким образом, ни один поток не может работать, пока не будет настроен последний. Мы используем boost.threads, и первое, что они делают, это ждать на boost::barrier
.
Я споткнулся с подобной проблемой однажды в свое время. Причины приостановленного начального состояния рассматриваются в другом ответе.
Мое решение с pthread состояло в использовании мьютекса и cond_wait
, но я не знаю, является ли это хорошим решением и может покрыть все возможные потребности. Более того, я не знаю, если поток можно считать приостановленным (в то время я считал "заблокированным" в руководстве как синоним, но, вероятно, это не так)