如何检查astd::thread
是否仍在运行(以独立于平台的方式)?它缺少一种timed_join()
方法,joinable()
并不意味着要这样做。
我曾考虑过std::lock_guard
在线程中使用a锁定互斥锁,并使用try_lock()
互斥锁的方法来确定它是否仍处于锁定状态(线程正在运行),但是这对我来说似乎不必要。
您知道更优雅的方法吗?
更新:要明确:我想检查线程是否干净退出。为此,一个“挂起”线程被认为正在运行。
如何检查astd::thread
是否仍在运行(以独立于平台的方式)?它缺少一种timed_join()
方法,joinable()
并不意味着要这样做。
我曾考虑过std::lock_guard
在线程中使用a锁定互斥锁,并使用try_lock()
互斥锁的方法来确定它是否仍处于锁定状态(线程正在运行),但是这对我来说似乎不必要。
您知道更优雅的方法吗?
更新:要明确:我想检查线程是否干净退出。为此,一个“挂起”线程被认为正在运行。
Answers:
如果您愿意使用C ++ 11std::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.
}
编辑:
另外还有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。然后,主线程可以检查该变量,如果为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 。
您可以使用这种简单的机制来检测线程的完成情况,而不会阻塞join方法。
std::thread thread([&thread]() {
sleep(3);
thread.detach();
});
while(thread.joinable())
sleep(1);
join()
从某个不等待该线程释放其joinable()
属性的线程中进行调用,否则它将无限循环(即,joinable()
返回true,直到该线程实际处于join()
ed直到完成为止)
thread.detach()
零件,则上面的程序将永远不会终止。
创建一个互斥量,正在运行的线程和调用线程都可以访问。当运行线程启动时,它将锁定互斥锁,当线程结束时,它将解锁互斥锁。要检查线程是否仍在运行,调用线程将调用mutex.try_lock()。那的返回值是线程的状态。(如果try_lock有效,请确保解锁互斥锁)
与此相关的一个小问题是,muttex.try_lock()在创建线程与锁定互斥锁之间将返回false,但是可以使用稍微复杂一些的方法来避免这种情况。
std::mutex
这种信号用于(主要是由于通常实现互斥锁的原因)。atomic_flag
在这种情况下,an的效果也很好,而开销却更少。Astd::future
可能会更好,因为它可以更清楚地表达意图。另外请记住,try_lock
可能会意外失败,所以回报是不是一定是线程的状态(虽然它可能不会太厉害了在这种特殊情况下)。
您始终可以检查线程的ID是否与默认构造的std :: thread :: id()不同。正在运行的线程始终具有真正的关联ID。尽量避免花哨的东西:)
当然,必须将互斥变量包装的变量初始化为false
,该线程true
在退出之前将其设置为最后要做的事情。这足以满足您的需求吗?
std::atomic<bool>
负责本作的你,这就是为什么它是真正的答案海事组织。
wait()
;如果是,则在wait()
尚未运行时,它必须按照定义运行。但是这种推理可能是不准确的。