Как проверить, работает ли std:: thread?
как я могу проверить, если std::thread
все еще работает (независимо от платформы)?
Ему не хватает timed_join()
способ и joinable()
не предназначен для этого.
Я думал о блокировке мьютекса с std::lock_guard
в потоке и с помощью try_lock()
метод мьютекса, чтобы определить, по-прежнему ли он заблокирован (поток запущен), но мне кажется излишне сложным.
знаете ли вы более элегантный метод?
обновление: для ясности: я хочу проверьте, вышел ли поток чисто или нет. Для этой цели считается "висячая" нить.
5 ответов
если вы готовы использовать 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
затем вы можете использовать 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.
}
оба этих примера выведут:
Thread still running
это, конечно, потому, что состояние потока проверяется перед задачей законченный.
но опять же, может быть, проще просто сделать это, как уже упоминали другие:
#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.
}
Edit:
есть еще 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.
}
простым решением является наличие булевой переменной, которую поток устанавливает в true через регулярные интервалы, и которая проверяется и устанавливается в false потоком, желающим знать состояние. Если переменная имеет значение false for to long, поток больше не считается активным.
более потокобезопасным способом является наличие счетчика, который увеличивается дочерним потоком, а основной поток сравнивает счетчик с сохраненным значением, и если то же самое после слишком долгого времени, то дочерний поток считается неактивным.
Примечание однако в C++11 нет способа фактически убить или удалить поток, который повесился.
редактировать Как проверить, вышел ли поток чисто или нет: в основном тот же метод, что описан в первом абзаце; имеют логическую переменную, инициализированную false. Последнее, что делает дочерний поток, это устанавливает его в true. Затем основной поток может проверить эту переменную, и если true, то соедините дочерний поток без особых усилий (если любой) блокировка.
Edit2 если поток выходит из-за исключения, то есть две "основные" функции потока: первая имеет try
-catch
внутри которого он вызывает вторую" реальную " функцию основного потока. Эта первая основная функция устанавливает переменную "have_exited". Что-то вроде этого:--4-->
bool thread_done = false;
void *thread_function(void *arg)
{
void *res = nullptr;
try
{
res = real_thread_function(arg);
}
catch (...)
{
}
thread_done = true;
return res;
}
этот простой механизм можно использовать для обнаружения окончания потока без блокировки в методе соединения.
std::thread thread([&thread]() {
sleep(3);
thread.detach();
});
while(thread.joinable())
sleep(1);
создайте мьютекс, к которому имеют доступ и текущий поток, и вызывающий поток. Когда запущенный поток запускается, он блокирует мьютекс, а когда он заканчивается, он разблокирует мьютекс. Чтобы проверить, работает ли поток, вызывающий поток вызывает мьютекс.try_lock(). Возвращаемое значение этого-состояние потока. (Просто убедитесь, что разблокировать мьютекс, если try_lock работал)
одна небольшая проблема с этим, мьютекс.try_lock () вернет false между временем потока создан, и когда он блокирует мьютекс, но этого можно избежать с помощью немного более сложного метода.
конечно, есть переменная, обернутая мьютексом, инициализированная false
, что поток устанавливается в true
как последнее, что он делает перед выходом. Этого достаточно для ваших нужд?