Подтвердить что ты не робот

Убить заблокированный Boost:: Thread

Я пишу приложение, которое блокируется при вводе из двух istreams.

Чтение из istream является синхронным (блокирующим) вызовом, поэтому я решил создать два Boost::thread для чтения.

Любой из этих потоков может перейти к "концу" (на основе некоторого введенного ввода), и как только достигнут "конец", оба входных потока прекращают прием. К сожалению, я не знаю, что будет делать.

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

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

Это их способ:

  • Отправьте сигнал boost:: thread или
  • Настроить istream на "fail" или
  • Убейте Boost:: thread?

Примечание:

  • Один из istreams - cin
  • Я пытаюсь перезапустить процесс, поэтому я не могу закрыть входные потоки таким образом, чтобы запретить их повторную передачу.

Edit:

  • Я знаю, когда достигнут "конец", и я знаю, какой поток успешно завершен, и который нужно убить. Его убийство мне нужно выяснить (или другую стратегию для чтения из istream).
  • Мне нужно, чтобы оба потока были правильно завершены и очищены: (

Спасибо!

4b9b3361

Ответ 1

Я не думаю, что есть способ сделать это кросс-платформой, но pthread_cancel должен быть тем, что вы ищете. С помощью потока boost вы можете получить native_handle из потока и вызвать pthread_cancel на нем.

Кроме того, лучшим способом может быть использование boost asio эквивалента выбора вызова для нескольких файлов. Таким образом, один поток будет заблокирован в ожидании ввода, но он может поступать из любого входного потока. Я не знаю, как легко сделать что-то подобное с помощью iostreams.

Ответ 2

Да, есть!

boost::thread::terminate() выполнит работу по вашим требованиям.

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

Прекращение не мгновенно. (В любом случае, неправильный поток работает в этот момент.)

Это происходит в заранее определенных условиях - наиболее удобным для вас будет, вероятно, при вызове boost::this_thread::sleep();, который вы могли бы периодически выполнять этот поток.

Ответ 3

Если поток повышения блокируется при операции ввода-вывода (например, cin>>whatever), boost::thread::terminate() не будет убивать поток. cin i/o не является допустимой точкой окончания. Поймать 22.

Ответ 4

Ну, на linux я использую pthread_signal (SIGUSR1), поскольку он прерывает блокировку IO. Там нет такого вызова в окнах, как я обнаружил при портировании моего кода. Только устаревший в вызове чтения сокета. В Windows вы должны явно определить событие, которое прервет ваш блокирующий вызов. Поэтому нет такой вещи (AFAIK) как общий способ прервать блокировку IO.

Конструкция boost.thread обрабатывает это, управляя хорошо идентифицированными точками прерывания. Я не знаю boost.asio, и кажется, что вы все равно не хотите полагаться на него. Если вы не хотите, чтобы рефакторинг использовал неблокирующую парадигму, что вы можете сделать, это использовать что-то между неблокированием (опросом) и блокировкой ввода-вывода. Это что-то вроде (псевдо-код?):

while(!stopped && !interrupted)
{
    io.blockingCall(timeout);
    if(!stopped && !interrupted)
    {
        doSomething();
    }
}

Затем вы прерываете свои два потока и присоединяете их...

Возможно, это проще в вашем случае? Если у вас есть основной поток, который знает, что один поток завершен, вам просто нужно закрыть IO другого потока?

Изменить: Кстати, меня интересует окончательное решение, которое у вас есть...

Ответ 5

У меня была аналогичная проблема и я пришел к этому решению, которое могут найти некоторые другие читатели этого вопроса:

Предполагая, что вы используете переменную condition с командой wait(), вам важно знать, что в Boost оператор wait() является естественной точкой прерывания. Поэтому просто поставьте блок try/catch вокруг кода с помощью оператора wait и позвольте функции нормально завершаться в вашем блоке catch.

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

Теперь все ваши потоки прекратятся изящно, и любая очистка памяти, связанной с Boost, должна работать чисто.

Ответ 6

Вместо того, чтобы пытаться убить ваш поток, вы всегда можете попытаться подключиться к потоку, и если он терпит неудачу, вы присоединитесь к другому. (Предполагая, что вы всегда сможете присоединиться хотя бы к одному из двух ваших потоков).

В boost: thread вы ищете функцию timed_join.

Если вы хотите посмотреть на правильный ответ, однако, это будет использовать неблокирующий io с временными ожиданиями. Позволяет получить структуру потока синхронного io с неблокированием асинхронного io.

Вы говорите о форме чтения istream, но istream - это только интерфейс. для stdin вы можете просто закрыть дескриптор файла stdin, чтобы прервать чтение. Что касается другого, это зависит от того, где вы читаете...

Ответ 7

В Windows используйте QueueUserAPC для очереди proc, которая выдает исключение. Этот подход отлично подходит для меня.

HOWEVER. Я только что обнаружил, что надменные мьютексы и т.д. не являются "предупреждаемыми" на win32, поэтому QueueUserAPC не может их прервать.

Ответ 8

Кажется, что нити не помогают вам делать то, что вы хотите простым способом. Если Boost.Asio вам не по душе, рассмотрите возможность использования select().

Идея состоит в том, чтобы получить два дескриптора файла и использовать select(), чтобы указать, какие из них имеют доступный вход. Дескриптор файла для cin обычно STDIN_FILENO; как получить другой, зависит от вашей специфики (если это файл, просто open() вместо использования ifstream).

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

Ответ 9

Очень поздно, но в Windows (и это прекурсоры, такие как VMS или RSX, для тех, кто помнит такие вещи), я бы использовал что-то вроде ReadFileEx с подпрограммой завершения, которая сигнализирует о завершении, и CancelIO, если чтение нужно отменить раньше,

Linux/BSD имеет совершенно другой базовый API, который не столь гибкий. Использование pthread_kill для отправки сигнала работает для меня, это остановит операцию чтения/открытия.

Для этой платформы стоит использовать другой код в этой области, IMHO.