Как я могу проверить, работает ли std::thread
еще (независимо от платформы)? У него нет timed_join()
метода, и joinable()
он не предназначен для этого.
Я думал заблокировать мьютекс с помощью a std::lock_guard
в потоке и использовать try_lock()
метод мьютекса, чтобы определить, заблокирован ли он по-прежнему (поток выполняется), но мне это кажется излишне сложным.
Вы знаете более изящный метод?
Обновление: для ясности: я хочу проверить, завершился ли поток чисто или нет. Для этой цели «висящая» нить считается запущенной.
c++
multithreading
c++11
stdthread
Kispaljr
источник
источник
wait()
и если это так, если вы еще этого не сделалиwait()
, он должен работать по определению. Но это рассуждение может быть неточным.Ответы:
Если вы хотите использовать C ++ 11
std::async
иstd::future
для выполнения своих задач, вы можете использоватьwait_for
функцию,std::future
чтобы проверить, работает ли все еще поток, таким аккуратным способом:#include <future> #include <thread> #include <chrono> #include <iostream> int main() { using namespace std::chrono_literals; /* Run some task on new thread. The launch policy std::launch::async makes sure that the task is run asynchronously on a new thread. */ auto future = std::async(std::launch::async, [] { std::this_thread::sleep_for(3s); return 8; }); // Use wait_for() with zero milliseconds to check thread status. auto status = future.wait_for(0ms); // Print status. if (status == std::future_status::ready) { std::cout << "Thread finished" << std::endl; } else { std::cout << "Thread still running" << std::endl; } auto result = future.get(); // Get result. }
Если вы должны использовать
std::thread
then, вы можете использоватьstd::promise
для получения будущего объекта:#include <future> #include <thread> #include <chrono> #include <iostream> int main() { using namespace std::chrono_literals; // Create a promise and get its future. std::promise<bool> p; auto future = p.get_future(); // Run some task on a new thread. std::thread t([&p] { std::this_thread::sleep_for(3s); p.set_value(true); // Is done atomically. }); // Get thread status using wait_for as before. auto status = future.wait_for(0ms); // Print status. if (status == std::future_status::ready) { std::cout << "Thread finished" << std::endl; } else { std::cout << "Thread still running" << std::endl; } t.join(); // Join thread. }
Оба этих примера выведут:
Это, конечно, связано с тем, что статус потока проверяется до завершения задачи.
Но опять же, может быть проще просто сделать это, как уже упоминалось другими:
#include <thread> #include <atomic> #include <chrono> #include <iostream> int main() { using namespace std::chrono_literals; std::atomic<bool> done(false); // Use an atomic flag. /* Run some task on a new thread. Make sure to set the done flag to true when finished. */ std::thread t([&done] { std::this_thread::sleep_for(3s); done = true; }); // Print status. if (done) { std::cout << "Thread finished" << std::endl; } else { std::cout << "Thread still running" << std::endl; } t.join(); // Join thread. }
Редактировать:
Есть также
std::packaged_task
для использования сstd::thread
более чистым решением, чем использованиеstd::promise
:#include <future> #include <thread> #include <chrono> #include <iostream> int main() { using namespace std::chrono_literals; // Create a packaged_task using some task and get its future. std::packaged_task<void()> task([] { std::this_thread::sleep_for(3s); }); auto future = task.get_future(); // Run task on new thread. std::thread t(std::move(task)); // Get thread status using wait_for as before. auto status = future.wait_for(0ms); // Print status. if (status == std::future_status::ready) { // ... } t.join(); // Join thread. }
источник
std::atomic<bool> done(false);
? Развеbool
по умолчанию не атомарный?std::atomic
.sizeof(bool)
определяется реализацией и может быть> 1, поэтому возможна частичная запись. Также существует проблема согласованности кеша ..Простое решение - иметь логическую переменную, которой поток устанавливает значение true через регулярные промежутки времени, и которая проверяется и устанавливается в значение false потоком, желающим узнать состояние. Если значение переменной равно false на слишком долгое время, поток больше не считается активным.
Более потокобезопасный способ - иметь счетчик, который увеличивается дочерним потоком, а основной поток сравнивает счетчик с сохраненным значением, и если то же самое по прошествии слишком длительного времени, дочерний поток считается неактивным.
Обратите внимание, однако, что в C ++ 11 нет способа фактически убить или удалить зависший поток.
Изменить Как проверить, завершился ли поток чисто или нет: В основном тот же метод, что описан в первом абзаце; Инициализировать логическую переменную значением false. Последнее, что делает дочерний поток, - устанавливает для него значение true. Затем основной поток может проверить эту переменную и, если это правда, выполнить соединение с дочерним потоком без особой блокировки (если таковая имеется).
Edit2 Если поток завершается из-за исключения, тогда есть две «основные» функции потока: у первой есть
try
-catch
внутри которой она вызывает вторую «настоящую» функцию основного потока. Эта первая основная функция устанавливает переменную have_exited. Что-то вроде этого:bool thread_done = false; void *thread_function(void *arg) { void *res = nullptr; try { res = real_thread_function(arg); } catch (...) { } thread_done = true; return res; }
источник
thread_done
, то этот код не работает без барьера памяти.std::atomic<bool>
Вместо этого используйте .bool
время, как основной поток читает из него - для этого нужен барьер памяти.std::atomic<bool>
необходим a .Этот простой механизм можно использовать для определения завершения потока без блокировки метода соединения.
std::thread thread([&thread]() { sleep(3); thread.detach(); }); while(thread.joinable()) sleep(1);
источник
join()
из какого-то потока, который не ждет, пока поток потеряет своеjoinable()
свойство, иначе он будет зацикливаться бесконечно (т.е.joinable()
возвращает истину, пока поток фактически неjoin()
ed и не до его завершения)thread.detach()
деталь, вышеуказанная программа никогда не завершится.Создайте мьютекс, к которому у запущенного и вызывающего потоков есть доступ. Когда запущенный поток запускается, он блокирует мьютекс, а когда он заканчивается, он разблокирует мьютекс. Чтобы проверить, работает ли поток, вызывающий поток вызывает mutex.try_lock (). Возвращаемое значение - это статус потока. (Просто убедитесь, что мьютекс разблокирован, если try_lock сработал)
Одна небольшая проблема с этим: mutex.try_lock () будет возвращать false между моментом создания потока и блокировкой мьютекса, но этого можно избежать, используя немного более сложный метод.
источник
std::mutex
для этого типа сигнализации (в основном по причинам, как обычно реализуется мьютекс). Вatomic_flag
этом случае An работает также с гораздо меньшими накладными расходами. Аstd::future
может быть даже лучше, поскольку он более четко выражает намерение. Кроме того, помните, что этоtry_lock
может привести к ложному сбою, поэтому возврат не обязательно является статусом потока (хотя в данном конкретном случае это, вероятно, не повредит вам).Вы всегда можете проверить, отличается ли идентификатор потока от созданного по умолчанию std :: thread :: id (). У запущенного потока всегда есть подлинный связанный идентификатор. Старайтесь избегать лишних наворотов :)
источник
Разумеется, инициализированная переменная, обернутая мьютексом
false
, устанавливается потокомtrue
в последнюю очередь перед завершением. Достаточно ли этого атомарного для ваших нужд?источник
std::atomic<bool>
позаботится об этом за вас, поэтому это настоящий ответ ИМО.