[英]Approach of using an std::atomic compared to std::condition_variable wrt pausing & resuming an std::thread in C++
我在我的C++
代码中使用std::thread
来不断轮询某些数据并将其添加到缓冲区。 我使用C++ lambda
来启动这样的线程:
StartMyThread() {
thread_running = true;
the_thread = std::thread { [this] {
while(thread_running) {
GetData();
}
}};
}
thread_running
是在类头中声明的atomic<bool>
。 这是我的GetData
函数:
GetData() {
//Some heavy logic
}
接下来我还有一个StopMyThread
函数,我将thread_running
设置为false,以便它退出lambda block
中的while循环。
StopMyThread() {
thread_running = false;
the_thread.join();
}
据我了解,我可以暂停和使用恢复该线程std::condition_variable
如指出, 这里在我前面的问题。
但是,如果我只是使用std::atomic<bool>
thread_running
来执行或不执行GetData()
的逻辑,那么是否存在缺点?
GetData() {
if (thread_running == false)
return;
//Some heavy logic
}
与使用 这里 描述的std::condition_variable
的方法相比,这会消耗更多的CPU周期 吗?
当您想要有条件地停止另一个线程时,条件变量很有用。 因此,您可能有一个始终运行的“工作线程”线程,当它注意到它无法运行时,它会等待。
原子解决方案要求您的UI交互与工作线程同步,或者非常复杂的逻辑以异步方式执行。
作为一般规则,您的UI响应线程永远不应该阻止工作线程的非就绪状态。
struct worker_thread {
worker_thread( std::function<void()> t, bool play = true ):
task(std::move(t)),
execute(play)
{
thread = std::async( std::launch::async, [this]{
work();
});
}
// move is not safe. If you need this movable,
// use unique_ptr<worker_thread>.
worker_thread(worker_thread&& )=delete;
~worker_thread() {
if (!exit) finalize();
wait();
}
void finalize() {
auto l = lock();
exit = true;
cv.notify_one();
}
void pause() {
auto l = lock();
execute = false;
}
void play() {
auto l = lock();
execute = true;
cv.notify_one();
}
void wait() {
Assert(exit);
if (thread)
thread.get();
}
private:
void work() {
while(true) {
bool done = false;
{
auto l = lock();
cv.wait( l, [&]{
return exit || execute;
});
done = exit; // have lock here
}
if (done) break;
task();
}
}
std::unique_lock<std::mutex> lock() {
return std::unique_lock<std::mutex>(m);
}
std::mutex m;
std::condition_variable cv;
bool exit = false;
bool execute = true;
std::function<void()> task;
std::future<void> thread;
};
或者某些。
这拥有一个主题。 只要处于play()
模式,线程就会重复运行任务。 如果您在下一次task()
完成时pause()
,则工作线程将停止。 如果在task()
调用完成之前play()
,则不会注意到pause()
。
唯一的等待是破坏worker_thread
,它会自动通知它应该退出的工作线程并等待它完成。
您也可以手动.wait()
或.finalize()
。 .finalize()
是异步的,但是如果你的应用程序正在关闭,你可以提前调用它,并让工作线程有更多的时间来清理,而主线程可以清理其他地方。
.finalize()
无法逆转。
代码未经测试。
除非我遗漏了什么,否则你已经在原来的问题中回答了这个问题:每次需要时你都会创建并销毁工作线程。 这可能是您实际申请中的问题,也可能不是。
有两个不同的问题正在解决,这可能取决于你实际在做什么。 一个问题是“我希望我的线程运行直到我告诉它停止。” 另一个似乎是“我有一个生产者/消费者对,并希望能够在数据准备好时通知消费者”。 thread_running
和join
方法适用于第一个。 第二个你可能想要使用互斥和条件,因为你所做的不仅仅是使用状态来触发工作。 假设你有一个vector<Work>
。 你使用互斥锁保护它,所以条件变为[&work] (){ return !work.empty(); }
[&work] (){ return !work.empty(); }
或类似的东西。 当等待返回时,你持有互斥锁,这样你就可以把事情搞砸了。 完成后,您将返回等待,释放互斥锁,以便生产者可以向队列添加内容。
您可能希望结合使用这些技术。 有一个“完成处理”原子,你的所有线程都会定期检查以确定何时退出,以便你可以加入它们。 使用条件来涵盖线程之间的数据传递情况。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.