在不使用自旋锁的情况下暂停空队列上的线程
Pausing thread on empty queue without using spinlock
我有一些代码是这样工作的:
std::queue<int> a_queue;
bool exit = false;
void MainThreadFunc(int somedata)
{
a_queue.push(somedata);
}
void WorkerThreadFunc()
{
while (true)
{
if (exit)
return;
while (a_queue.empty());
DoSomethingWithData(a_queue.front());
a_queue.pop();
}
}
问题是,我的CPU使用率非常高,这似乎是由于工作线程无事可做时的自旋锁。我试图使用互斥锁,但我需要主线程在队列中无事时锁定它(当然,这是不可能的)。有什么替代方案可以防止这种情况发生?
下面的代码是我之前在其他地方学到的。它是一个阻塞队列实现。线程可以安全地将元素放入队列,如果某个线程试图在元素为空时从队列中取出元素,则它将被阻止,直到其他线程将元素放入该队列。希望它能帮助你
#include <queue>
#include <cassert>
#include <mutex>
#include <condition_variable>
#include <thread>
template<typename T>
class BlockingQueue
{
private:
std::mutex _mutex;
std::condition_variable _condvar;
std::queue<T> _queue;
public:
BlockingQueue(): _mutex(),_condvar(),_queue()
{
}
BlockingQueue(const BlockingQueue& rhs) = delete;
BlockingQueue& operator = (const BlockingQueue& rhs) = delete;
void Put(const T& task)
{
{
std::lock_guard<std::mutex> lock(_mutex);
_queue.push(task);
}
_condvar.notify_all();
}
T Take()
{
std::unique_lock<std::mutex> lock(_mutex);
_condvar.wait(lock,[this]{return !_queue.empty(); });
assert(!_queue.empty());
T front(std::move(_queue.front()));
_queue.pop();
return front;
}
};
考虑到线程调度程序/上下文切换的成本过于昂贵的既定要求,通常最好的选择是像现在这样简单地燃烧周期,以满足最严格的延迟要求。
原子CAS自旋/繁忙循环基本上是一种轮询方法,通常与轮询相关,它有占用CPU的趋势。然而,它并没有支付调度器的成本,而在16毫秒的最后期限内,你需要完成所有需要做的事情并交付一个帧,这是你想要避免的。这通常是你最好的选择,以满足这种最后期限。
在游戏中,你有一个生动的世界和不断的动画内容,通常不会有长时间的无所事事。因此,对于一个不断使用CPU的游戏来说,这通常被认为是可以接受的。
考虑到您的需求,可能一个更有效的问题不是如何降低CPU利用率,而是确保CPU利用率达到良好的目的。通常,并发队列可以提供一个无锁、无阻塞的查询来检查队列是否为空,您似乎已经给出了以下行:
while (a_queue.empty());
当队列为空时,您可能可以偷偷地在这里计算一些东西。这样一来,您就不会仅仅忙于等待队列变为非空而占用周期。
同样,你的问题的理想答案通常包括一个条件变量(这取决于上下文开关和被唤醒的线程)。这通常是让线程进入睡眠状态(降低CPU利用率)并在所需时间唤醒线程的最快方法,但考虑到延迟要求很高,最好忘记CPU利用率,更多地关注确保它达到良好的目的。
std::queue
不是线程安全的。正如@Hurkyl发布的那样,如果你想使用std::queue
,你需要一个锁。
按照编码,如果多个线程在队列中等待数据,它们可以所有都对a_queue.fronf()
中的同一个值执行操作,然后多次调用a_queue.pop()
,与推送到队列上的值的数量无关。
请参阅STL队列的线程安全
- 在没有太多条件句的情况下,我如何避免被零除
- 为什么在没有显式默认构造函数的情况下,将另一个结构封装在联合中作为成员的结构不能编译
- 在未初始化映射的情况下,将值插入到映射的映射中
- 是默认情况下分配给char数组常量的值
- 为什么我不能在不创建字符串变量的情况下使用函数的字符串输出
- 如何在不产生任何垃圾的情况下获得C中的像素
- 在已经使用Git的情况下减少编译时间
- 为什么在Windows上的VS 2019和Clang 9中"size_t"在没有标题的情况下工作
- 如何在没有信号的情况下从C++执行QML插槽
- 如何在不知道向量大小的情况下输入向量内部的向量?
- 为什么在某些情况下不写入此文件?
- 为什么Mat类的两个对象可以在不重载运算符+的情况下添加
- 在没有Xcode的情况下在Mac捆绑包中嵌入框架
- UE4-如何在给定4个屏幕坐标的情况下缩放纹理或材质
- 如何在不接触函数本身的情况下暂停和恢复 C++11 std::thread 的功能
- 有没有办法在没有"entering key"的情况下等待并暂停程序?
- 在不暂停贪吃蛇游戏的情况下获取输入
- 如何在不暂停循环的情况下使用字符输入停止循环
- 在不使用自旋锁的情况下暂停空队列上的线程
- Linux:有没有一种方法可以在不停止/暂停进程的情况下使用ptrace(SIGSTOP)