Согласно C++ 0x заключительный проект, нет никакого способа запросить поток завершиться. Тем не менее при необходимости мы должны реализовать самостоятельное решение.
С другой стороны, повышение:: поток обеспечивает механизм для прерывания потока безопасным способом.
По Вашему мнению, каково лучшее решение? Разработка собственного совместного 'механизма прерывания' или движение собственного компонента?
Вся спецификация языка говорит о том, что поддержка не встроена в язык.
boost::thread::interrupt
нуждается в некоторой поддержке и со стороны функции потока:
Когда прерванный поток в следующий раз выполнит одну из указанных точек прерывания (или если он в данный момент заблокирован при выполнении одной из них)
т.е. когда функция потока не дает вызывающей стороне шанса прерваться, вы все равно застреваете.
Я не уверен, что вы имеете в виду под "переходом на родной язык" - нет никакой нативной поддержки, если только вы не околдованы boost:threads
.
Тем не менее, я бы использовал явный механизм. Вам все равно приходится думать о достаточном количестве точек прерывания, почему бы не сделать их явными? По моему опыту, дополнительный код обычно незначительный, хотя вам, возможно, придется изменить некоторые ожидания с однообъектных на многообъектные, что - в зависимости от вашей библиотеки - может выглядеть более уродливо.
Можно также использовать "не использовать исключения для потока управления", но по сравнению с возней с потоками это просто рекомендации.
Завершать поток небезопасно, поскольку вы не можете контролировать состояние каких-либо данных - конструкции в это время велись.
Если вы хотите прервать запущенный поток, вы должны реализовать свой собственный механизм. ИМХО, если вам это нужно, ваш дизайн не подготовлен для нескольких потоков.
Если вы просто хотите дождаться завершения потока, используйте join () или future.
Я согласен с этим решением. Например, .NET позволяет прерывать любой рабочий поток, и я никогда не использую эту функцию и не рекомендую делать это ни одному профессиональному программисту. Я хочу сам решить, когда рабочий поток может быть прерван, и как это сделать. Он отличается для оборудования, ввода-вывода, пользовательского интерфейса и других потоков. Если поток может быть остановлен в любом месте, это может привести к неопределенному поведению программы с управлением ресурсами, транзакциями и т. Д.
Реализация решения «сделай сам» имеет наибольший смысл, и это действительно не должно быть так сложно. Вам понадобится общая переменная, которую вы читаете / записываете синхронно, указывая, запрашивается ли завершение потока, и ваш поток периодически читает из этой переменной, когда он находится в состоянии, когда его можно безопасно прервать. Когда вы хотите прервать поток, вы просто синхронно записываете в эту переменную, а затем присоединяетесь к потоку. Предполагая, что он правильно взаимодействует, он должен заметить, что переменная была записана и закрыта, в результате чего функция соединения больше не блокируется.
Если бы вы стали туземцем, вы бы ничего от этого не получили; вы бы просто выбросили все преимущества стандартного и кроссплатформенного механизма потоковой передачи ООП. Для того, чтобы ваш код был правильным, поток должен быть завершен совместно, что подразумевает взаимодействие, описанное выше.
Опережающее завершение потока небезопасно, потому что состояние всего процесса после этого момента становится неопределенным. Поток мог получить критическую секцию до того, как был завершен. Этот критический раздел теперь никогда не будет выпущен. Куча может быть заблокирована навсегда и т. Д.
Решение boost :: thread :: interrupt
работает правильно, задавая вопросы. Он только прерывает поток, выполняющий что-то, что можно прервать, например, ожидание переменной условия Boost.Thread, или если поток выполняет одно из этих действий после вызова прерывания. Даже в этом случае поток не проходит бесцеремонно через мясорубку, как, скажем, функция Win32 TerminateThread
, он просто вызывает исключение, которое, если вы хорошо себя вели кодировщик и использовали RAII везде, уберет за собой и изящно выйдет из потока.
Использование собственного дескриптора для отмены thread - плохой вариант в C ++, так как вам нужно уничтожить все выделенные объекты стека. Это была основная причина, по которой они не включали операцию отмены.
Boost.Thread предоставляет механизм прерывания, который необходимо объединить в любой ожидающий примитив. Поскольку это обычный механизм может быть дорогостоящим, стандарт не включил его.
Вам нужно будет реализовать это самостоятельно. См. Мой ответ здесь на аналогичный вопрос о том, как реализовать это самостоятельно. Чтобы завершить решение, следует бросить прерывание, когда прерывание истинно, и поток должен уловить это прерывание и закончить.
В моей реализации потоков используется идиома pimpl, а в классе Impl у меня есть одна версия для каждой поддерживаемой мной ОС, а также версия с ускорением, поэтому я может решить, какой из них использовать при построении проекта.
Я решил создать два класса: один - это Thread, который имеет только базовые службы, предоставляемые ОС; а другой - SafeThread, который наследуется от Thread и имеет метод коллективного прерывания.
В потоке есть метод terminate (), который выполняет принудительное завершение. Это виртуальный метод, который перегружен в SafeThread, где он сигнализирует об объекте события. Существует (статический) метод yeld (), который время от времени должен вызывать запущенный поток; эти методы проверяют, сигнализируется ли объект события, и, если да, генерирует исключение, перехваченное в вызывающей стороне точки входа потока, тем самым завершая поток. Когда это происходит, он сигнализирует второму объекту события, поэтому вызывающий terminate () может знать, что поток был безопасно остановлен.
В случаях, когда существует риск тупиковой ситуации, SafeThread :: terminate () может принимать параметр тайм-аута. Если время ожидания истекает, он вызывает Thread :: terminate (), таким образом, интрузивно убивая поток. Это последний ресурс, когда у вас есть что-то, что вы не можете контролировать (например, сторонний API), или в ситуациях, когда взаимоблокировка наносит больший ущерб, чем утечки ресурсов и тому подобное.
Надеюсь, это будет полезно для вашего решения и даст вам достаточно ясное представление о моем выборе дизайна. Если нет, могу выложить фрагменты кода, чтобы уточнить, если хотите.