在 C++ 中的线程内启动和停止循环
Posted
技术标签:
【中文标题】在 C++ 中的线程内启动和停止循环【英文标题】:Start and Stop a loop within a Thread in C++ 【发布时间】:2012-08-17 14:44:01 【问题描述】:我需要从一个事件开始循环,然后从另一个事件停止它。 我的想法是当我按下按钮时调用函数 startDequeuing(),以便启动一个带有循环的线程,然后终止这个循环,将函数 stopDequeuing() 中的“出队”变量设置为 false。
这是我第一次使用线程,当我开始循环时程序会锁定,我认为是因为变量“出队”被锁定并且无法从线程外部访问,对吗?
我该如何解决这个问题??
这里有一些代码:
void CameraManager::startDequeuing()
dequeuing = true;
std::thread dequeueThread(&CameraManager::dequeueLoop, this);
dequeueThread.join();
void CameraManager::stopDequeuing()
dequeuing = false;
void *CameraManager::dequeueLoop()
while(dequeuing)
highSpeedCamera->dequeue();
highSpeedCamera->enqueue();
【问题讨论】:
不,请不要使用 volatile,当它涉及到多线程时。它可能有效,但在正确编写的多线程应用程序中永远不需要它。这里的问题很可能是 stopDequeuing() 永远不会被调用,因为 startDequeing() 在 join() 上阻塞。 【参考方案1】:使用线程的全部意义在于让多个函数并行运行。这里:
std::thread dequeueThread(&CameraManager::dequeueLoop, this);
dequeueThread.join();
您启动第二个线程并让第一个线程进入睡眠状态,等待生成的线程返回。所以你仍然只有一个线程在运行。如果您有这种 GUI 事件循环,您可能会锁定添加回调的可能性,当该事件循环为空时,该回调将被调用。这可能使您可以在不使用线程的情况下做您想做的事情。
解决方案可能如下所示:
void CameraManager::startDequeuing()
dequeuing = true;
dequeueThread = std::thread(&CameraManager::dequeueLoop, this);
void CameraManager::stopDequeuing()
std::lock_guard<std::mutex> lock( mutex );
dequeuing = false;
dequeueThread.join();
bool CameraManager::keepOnDequeuing()
std::lock_guard<std::mutex> lock( mutex );
return dequeuing;
void *CameraManager::dequeueLoop()
while( keepOnDequeuing() )
highSpeedCamera->dequeue();
highSpeedCamera->enqueue();
【讨论】:
您在startDequeing
中缺少一个锁 - 如果您在start
和stop
中有锁,为什么要为keepOnDequeuing
添加keepOnDequeuing
just 为dequeueLoop
而不是那里的另一个锁?另外,您的线程仍然在startDequeuing
的范围内?!
@Dave 在启动线程之前没有锁定互斥锁是可以的,因为线程保证在线程启动之前看到对内存所做的更改。我添加了 keepOnDequeuing() 来制作 mutex.lock();读取标志; mutex.unlock() 更具可读性。尝试在没有那个帮助器的情况下编写 dequeueLoop() ,你会明白我的意思;-) lock_guard 将互斥锁锁定在它的 c'tor 中并在它的 d'tor 中解锁它,所以当名为 lock 的局部变量超出范围时,互斥锁已解锁()。
如果您不创建一个立即死亡的线程,您将需要互斥锁。而且,我知道 lock_guard 做什么,我没有问。
@Dave,没有创建线程,立即死亡。临时线程变量只是意味着你不能再指向那个线程,所以你不能 join() 例如。但是你是对的,dequeueThread 必须有一个成员变量,并且启动线程应该是 `dequeueThread = std::thread(&CameraManager::dequeueLoop, this);'
谢谢大家!我首先实现了 Torsten 提出的解决方案,当然将“dequeueThread”声明为一个类变量,并且效果很好!现在正如 Pete Becker 所建议的那样,我正在尝试使用 atomic bool 来提高性能。【参考方案2】:
你的程序死锁是因为join()
会阻塞直到你的线程函数完成;而且它永远不会在那个时候完成,因为它正在有效地执行while(true)
。
您希望dequeueThread
成为您班级的成员。为什么你希望它只在startDequeuing
的范围内存活?
【讨论】:
【参考方案3】:将dequeing
定义为原子布尔值:
#include <atomic>
std::atomic_bool dequeing = false;
它比使用互斥锁要快得多,并且可以获得相同的同步。
【讨论】:
忘了说:std::atomic_bool
也可以拼成std::atomic<bool>
。以上是关于在 C++ 中的线程内启动和停止循环的主要内容,如果未能解决你的问题,请参考以下文章