如何退出后台线程循环
How to exit from a background thread loop?
我有一个用于上传文件的后台线程。它是循环运行的;它做一些工作,然后休眠,直到超时或通过条件变量明确通知它还有更多的工作要做。问题是有时我无法让线程快速退出。
这是一个简化版本:
std::thread g_thread;
std::mutex g_mutex;
std::condition_variable g_cond;
bool g_stop = false;
void threadLoop()
{
while (!g_stop)
{
printf("doing some stuffn");
std::unique_lock<std::mutex> lock(g_mutex);
g_cond.wait_for(lock, std::chrono::seconds(15));
}
}
int main(int argc, char* argv[])
{
g_stop = false;
g_thread = std::thread(threadLoop);
printf("hellon");
g_stop = true;
g_cond.notify_one();
g_thread.join();
}
当我运行这个测试程序时,我希望它能很快退出,但有时它会卡在wait_forr((中。我认为notify_one((可能发生在线程在wait_fr((中休眠之前,但在检查g_stop之后。
有没有一个简单的解决方案,或者另一种更有效的设计模式?
在没有任何同步的情况下读取和写入g_stop
变量(例如使用原子操作或使用互斥体序列化对它的访问(。这是一场数据竞赛,是一种未定义的行为。
因为不能安全地访问它,所以编译器可以假设没有其他线程修改过g_stop
,所以在threadLoop
函数中,它可以将它加载到寄存器中一次,然后再也不读取变量,而只是保持循环。
为了确保循环线程能够看到对变量的写入,您应该使用std::atomic<bool>
或在对该变量的所有读取/写入之前锁定互斥对象。如果您使用atomic<bool>
来修复未定义的行为,但不能确保线程不会等待条件变量,因为正如您所建议的,在检查g_stop
的值和进入睡眠之间有一个窗口,在这个窗口中,主线程可以设置g_stop = true
并向condvar发信号,因此循环线程不会等到notify_one((调用之后,因此会错过它。
这个稍微改变的版本将确保线程不会等待条件变量,如果主线程已经告诉它停止:
std::thread g_thread;
std::mutex g_mutex;
std::condition_variable g_cond;
bool g_stop = false;
void threadLoop()
{
std::unique_lock<std::mutex> lock(g_mutex);
while (!g_stop)
{
printf("doing some stuffn");
g_cond.wait_for(lock, std::chrono::seconds(15));
}
}
int main(int argc, char* argv[])
{
g_stop = false;
g_thread = std::thread(threadLoop);
printf("hellon");
{
std::lock_guard<std::mutex> lock(g_mutex);
g_stop = true;
}
g_cond.notify_one();
g_thread.join();
}
这是因为循环线程在检查g_stop
时对互斥锁持有锁,并且一直持有该锁,直到开始等待condvar。主线程获取锁来设置g_stop = true
,这只能在其他线程等待时进行。
这意味着现在只有两次可能的处决。g_stop = true
发生在线程等待condvar时,它要么在notify_one((调用之前唤醒,要么因为notify_none((调用的而唤醒,但在这两种情况下,它都会立即看到g_stop == true
并停止循环。
- 目标C++,如何在后台线程中使用运行循环?
- 零MQ 后台线程创建
- CredUIPromptForWindowsCredentials在后台线程中引发Microsoft C++未经处理的异
- 继承、后台线程和 RAII
- 在 Unity 中C++使用后台线程进行图像处理会导致崩溃
- 防止sleep_for阻止后台线程
- 有没有一种简单的方法可以使用SFML在后台线程中播放声音
- glewInit 从后台线程调用时失败
- 使用pthreads时的后台线程(不错,优先级)
- 使用QThread运行可管理后台线程的正确方式
- c++允许后台线程在退出应用程序之前完成
- MFC C++后台线程
- Kinect SDK 在后台线程上崩溃,原因不明
- 如何在后台线程上正确设置全局鼠标挂钩
- 在后台线程上创建的调度程序未关闭时会发生什么情况?如何确保调度程序已正确关闭
- 通过C++从后台线程错误修改自动布局引擎
- 带有pthreads的后台线程
- 实现低优先级后台线程的模式
- 如何退出后台线程循环
- UI和后台线程之间的交叉线程