Как мне прекратить поток в C++11?
Мне не нужно правильно завершать поток или заставлять его отвечать на команду "завершить". Я заинтересован в принудительном завершении потока, используя чистый C++11.
7 ответов
Вы могли бы позвонить
std::terminate()
из любого потока, и поток, на который вы ссылаетесь, будет принудительно завершен.Вы могли бы организовать
~thread()
быть выполненным на объекте целевого потока, без вмешательстваjoin()
ниdetach()
на этом объекте. Это будет иметь тот же эффект, что и вариант 1.Вы можете создать исключение, которое имеет деструктор, который выбрасывает исключение. И затем организуйте, чтобы целевой поток генерировал это исключение, когда оно должно быть принудительно завершено. Сложность в том, чтобы заставить целевой поток выдать это исключение.
Опции 1 и 2 не пропускают внутрипроцессные ресурсы, но они завершают каждый поток.
Вариант 3, вероятно, приведет к утечке ресурсов, но частично совместен в том смысле, что целевой поток должен согласиться выдать исключение.
В C++11 (о котором я знаю) не существует переносимого способа некооперативного уничтожения одного потока в многопоточной программе (т.е. без уничтожения всех потоков). Не было мотивации для разработки такой функции.
std::thread
может иметь эту функцию-член:
native_handle_type native_handle();
Вы можете использовать это для вызова зависимой от ОС функции, которая делает то, что вы хотите. Например, в ОС Apple эта функция существует и native_handle_type
это pthread_t
, Если вы добились успеха, вы, скорее всего, утечки ресурсов.
Ответ @Howard Hinnant является правильным и всеобъемлющим. Но это может быть неправильно понято, если оно прочитано слишком быстро, потому что std::terminate()
(весь процесс) имеет то же имя, что и термин "прекращение", который имел в виду @AlexanderVX (1 поток).
Резюме: "прекратить 1 поток + принудительно (целевой поток не взаимодействует) + чистый C++11 = нет пути."
Я предполагаю, что поток, который нужно убить, находится либо в любом режиме ожидания, либо выполняет какую-то тяжелую работу. Я бы предложил использовать "наивный" способ.
Определите некоторые глобальные логические:
std::atomic_bool stop_thread_1 = false;
Поместите следующий код (или аналогичный) в несколько ключевых точек таким образом, чтобы он вызывал возврат всех функций в стеке вызовов до естественного завершения потока:
if (stop_thread_1)
return;
Затем, чтобы остановить поток из другого (основного) потока:
stop_thread_1 = true;
thread1.join ();
stop_thread_1 = false; //(for next time. this can be when starting the thread instead)
Советы по использованию OS-зависимой функции для завершения потока C++:
std::thread::native_handle()
только может получить действительный собственный тип дескриптора потока перед вызовомjoin()
или жеdetach()
, После этого,native_handle()
возвращает 0 -pthread_cancel()
будет coredump.Для эффективного вызова собственной функции завершения потока (например,
pthread_cancel)
Вам нужно сохранить родной дескриптор перед вызовомstd::thread::join()
или жеstd::thread::detach()
, Так что ваш родной терминатор всегда имеет действительный дескриптор для использования.
Дополнительные пояснения можно найти по адресу: http://bo-yang.github.io/2017/11/19/cpp-kill-detached-thread.
Этот вопрос на самом деле имеет более глубокую природу, и хорошее понимание концепции многопоточности в целом даст вам понимание этой темы. На самом деле нет ни одного языка или какой-либо операционной системы, которая предоставляла бы вам средства для внезапного прерывания потока без предупреждения, чтобы не использовать их. И все эти среды выполнения настоятельно рекомендуют разработчику или даже требуют создания многопоточных приложений на основе кооперативного или синхронного завершения потока. Причина таких распространенных решений и советов заключается в том, что все они построены на основе одной и той же общей модели многопоточности.
Давайте сравним концепции многопроцессорности и многопоточности, чтобы лучше понять преимущества и недостатки второго.
Многопроцессорность предполагает разделение всей среды выполнения на множество полностью изолированных процессов, управляемых операционной системой. Процесс включает и изолирует состояние среды выполнения, включая локальную память процесса и данные внутри него, а также все системные ресурсы, такие как файлы, сокеты, объекты синхронизации. Изоляция является критически важной характеристикой процесса, поскольку она ограничивает распространение разломов по границам процесса. Другими словами, ни один процесс не может повлиять на согласованность любого другого процесса в системе. То же самое верно для поведения процесса, но менее ограниченным и более размытым способом. В такой среде любой процесс может быть убит в любой "произвольный" момент, потому что, во-первых, каждый процесс изолирован, во-вторых, операционная система обладает полными знаниями обо всех ресурсах, используемых процессом, и может высвободить все из них без утечки, и, наконец, процесс будет уничтожен. ОС на самом деле не в произвольный момент, а в количестве четко определенных точек, в которых состояние процесса хорошо известно.
Напротив, многопоточность предполагает запуск нескольких потоков в одном процессе. Но все эти потоки находятся в одном и том же изоляционном блоке, и операционная система не контролирует внутреннее состояние процесса. В результате любой поток может изменить состояние глобального процесса, а также повредить его. В то же время точки, в которых состояние потока, как известно, является безопасным для уничтожения потока, полностью зависят от логики приложения и не известны ни для операционной системы, ни для среды выполнения языка программирования. В результате завершение потока в произвольный момент означает уничтожение его в произвольной точке его пути выполнения и может легко привести к повреждению данных всего процесса, утечке памяти и обработчиков, утечке потоков и спин-блокировкам и другим примитивам синхронизации внутри процесса, оставшимся в закрытое состояние, препятствующее продвижению других потоков.
В связи с этим общий подход заключается в том, чтобы заставить разработчиков реализовать синхронное или совместное завершение потока, когда один поток может запросить завершение другого потока, а другой поток в четко определенной точке может проверить этот запрос и запустить процедуру завершения работы из четко определенного состояния. с высвобождением всех глобальных общесистемных ресурсов и локальных общесистемных ресурсов безопасным и последовательным способом.
Может TerminateThread? Только в окнах.
WINBASEAPI WINBOOL WINAPI TerminateThread (HANDLE hThread, DWORD dwExitCode);
Вы не можете использовать деструктор C++ std::thread для завершения одного потока в многопоточной программе. Вот соответствующий фрагмент кода деструктора std::thread, расположенный вthread
заголовочный файл (Visual C++):
~thread()
{
if (joinable())
std::terminate();
}
Если вы вызываете деструктор присоединяемого потока, деструктор вызывает std::terminate() , который воздействует на процесс; не в потоке, иначе он ничего не делает.
Можно «принудительно завершить поток» (C++11 std::thread) с помощью функции ОС. В Windows вы можете использовать TerminateThread. «это опасная функция, которую следует использовать только в самых крайних случаях». - Майкрософт | Учиться.
TerminateThread(tr.native_handle(), 1);
Для того, чтобы воздействовать, не следует вызывать / перед, так как такой вызов обнулитnative_handle()
.
Вы должны позвонитьdetach()
(илиjoin()
) послеTerminateThread
. В противном случае, как написано в 1-м абзаце, в деструкторе потокаstd::terminate()
будет вызван, и весь процесс будет завершен.
Пример:
#include <iostream>
#include <thread>
#include <Windows.h>
void Work10Seconds()
{
std::cout << "Work10Seconds - entered\n";
for (uint8_t i = 0; i < 20; ++i) {
std::this_thread::sleep_for(std::chrono::milliseconds(500));
std::cout << "Work10Seconds - working\n";
}
std::cout << "Work10Seconds - exited\n";
}
int main() {
std::cout << "main - started\n";
std::thread tr{};
std::cout << "main - Run 10 seconds work thread\n";
tr = std::thread(Work10Seconds);
std::cout << "main - Sleep 2 seconds\n";
std::this_thread::sleep_for(std::chrono::seconds(2));
std::cout << "main - TerminateThread\n";
TerminateThread(tr.native_handle(), 1);
tr.detach(); // After TerminateThread
std::cout << "main - Sleep 2 seconds\n";
std::this_thread::sleep_for(std::chrono::seconds(2));
std::cout << "main - exited\n";
}
Выход:
main - started
main - Run 10 seconds work thread
main - Sleep 2 seconds
Work10Seconds - entered
Work10Seconds - working
Work10Seconds - working
Work10Seconds - working
main - TerminateThread
main - Sleep 2 seconds
main - exited