C++ 0x распараллеливает прерывание

Согласно C++ 0x заключительный проект, нет никакого способа запросить поток завершиться. Тем не менее при необходимости мы должны реализовать самостоятельное решение.

С другой стороны, повышение:: поток обеспечивает механизм для прерывания потока безопасным способом.

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

56
задан Nicola Bonelli 9 May 2010 в 12:06
поделиться

7 ответов

Вся спецификация языка говорит о том, что поддержка не встроена в язык. boost::thread::interrupt нуждается в некоторой поддержке и со стороны функции потока:

Когда прерванный поток в следующий раз выполнит одну из указанных точек прерывания (или если он в данный момент заблокирован при выполнении одной из них)

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

Я не уверен, что вы имеете в виду под "переходом на родной язык" - нет никакой нативной поддержки, если только вы не околдованы boost:threads.

Тем не менее, я бы использовал явный механизм. Вам все равно приходится думать о достаточном количестве точек прерывания, почему бы не сделать их явными? По моему опыту, дополнительный код обычно незначительный, хотя вам, возможно, придется изменить некоторые ожидания с однообъектных на многообъектные, что - в зависимости от вашей библиотеки - может выглядеть более уродливо.


Можно также использовать "не использовать исключения для потока управления", но по сравнению с возней с потоками это просто рекомендации.

16
ответ дан 26 November 2019 в 17:31
поделиться

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

Если вы хотите прервать запущенный поток, вы должны реализовать свой собственный механизм. ИМХО, если вам это нужно, ваш дизайн не подготовлен для нескольких потоков.

Если вы просто хотите дождаться завершения потока, используйте join () или future.

6
ответ дан 26 November 2019 в 17:31
поделиться

Я согласен с этим решением. Например, .NET позволяет прерывать любой рабочий поток, и я никогда не использую эту функцию и не рекомендую делать это ни одному профессиональному программисту. Я хочу сам решить, когда рабочий поток может быть прерван, и как это сделать. Он отличается для оборудования, ввода-вывода, пользовательского интерфейса и других потоков. Если поток может быть остановлен в любом месте, это может привести к неопределенному поведению программы с управлением ресурсами, транзакциями и т. Д.

2
ответ дан 26 November 2019 в 17:31
поделиться

Реализация решения «сделай сам» имеет наибольший смысл, и это действительно не должно быть так сложно. Вам понадобится общая переменная, которую вы читаете / записываете синхронно, указывая, запрашивается ли завершение потока, и ваш поток периодически читает из этой переменной, когда он находится в состоянии, когда его можно безопасно прервать. Когда вы хотите прервать поток, вы просто синхронно записываете в эту переменную, а затем присоединяетесь к потоку. Предполагая, что он правильно взаимодействует, он должен заметить, что переменная была записана и закрыта, в результате чего функция соединения больше не блокируется.

Если бы вы стали туземцем, вы бы ничего от этого не получили; вы бы просто выбросили все преимущества стандартного и кроссплатформенного механизма потоковой передачи ООП. Для того, чтобы ваш код был правильным, поток должен быть завершен совместно, что подразумевает взаимодействие, описанное выше.

5
ответ дан 26 November 2019 в 17:31
поделиться

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

Решение boost :: thread :: interrupt работает правильно, задавая вопросы. Он только прерывает поток, выполняющий что-то, что можно прервать, например, ожидание переменной условия Boost.Thread, или если поток выполняет одно из этих действий после вызова прерывания. Даже в этом случае поток не проходит бесцеремонно через мясорубку, как, скажем, функция Win32 TerminateThread , он просто вызывает исключение, которое, если вы хорошо себя вели кодировщик и использовали RAII везде, уберет за собой и изящно выйдет из потока.

6
ответ дан 26 November 2019 в 17:31
поделиться

Использование собственного дескриптора для отмены thread - плохой вариант в C ++, так как вам нужно уничтожить все выделенные объекты стека. Это была основная причина, по которой они не включали операцию отмены.

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

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

10
ответ дан 26 November 2019 в 17:31
поделиться

В моей реализации потоков используется идиома pimpl, а в классе Impl у меня есть одна версия для каждой поддерживаемой мной ОС, а также версия с ускорением, поэтому я может решить, какой из них использовать при построении проекта.

Я решил создать два класса: один - это Thread, который имеет только базовые службы, предоставляемые ОС; а другой - SafeThread, который наследуется от Thread и имеет метод коллективного прерывания.

В потоке есть метод terminate (), который выполняет принудительное завершение. Это виртуальный метод, который перегружен в SafeThread, где он сигнализирует об объекте события. Существует (статический) метод yeld (), который время от времени должен вызывать запущенный поток; эти методы проверяют, сигнализируется ли объект события, и, если да, генерирует исключение, перехваченное в вызывающей стороне точки входа потока, тем самым завершая поток. Когда это происходит, он сигнализирует второму объекту события, поэтому вызывающий terminate () может знать, что поток был безопасно остановлен.

В случаях, когда существует риск тупиковой ситуации, SafeThread :: terminate () может принимать параметр тайм-аута. Если время ожидания истекает, он вызывает Thread :: terminate (), таким образом, интрузивно убивая поток. Это последний ресурс, когда у вас есть что-то, что вы не можете контролировать (например, сторонний API), или в ситуациях, когда взаимоблокировка наносит больший ущерб, чем утечки ресурсов и тому подобное.

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

4
ответ дан 26 November 2019 в 17:31
поделиться
Другие вопросы по тегам:

Похожие вопросы: