我有一些像这样的代码:
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占用率非常高,这似乎是自旋锁的结果,而工作人员什么也没做。我试图使用互斥锁,但是当队列中没有任何东西时,它需要主线程锁定它(当然,这不可能发生)。有什么替代方法可以防止这种情况发生?
答案 0 :(得分:0)
以下代码是我在其他地方之前学到的。它是一个阻塞队列工具。线程可以安全地将元素放入队列,如果线程在空时尝试从队列中获取元素,它将被阻塞,直到某个其他线程将元素放入队列。希望它可以帮到你
#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;
}
};
答案 1 :(得分:0)
鉴于规定的要求,线程调度程序/上下文切换的成本太高,通常最好的办法就是像现在一样简单地刻录循环,以满足最严格的延迟需求。
原子CAS旋转/忙碌循环基本上是一种轮询方法,并且通常与轮询相关,它具有占用CPU的趋势。然而,它并没有支付你想要避免的调度程序的成本,在16ms的最后期限内完成你需要做的所有事情并提供一个框架。通常,这是满足这种截止日期的最佳选择。
对于拥有生动世界和不断动画内容的游戏,通常没有任何事情发生的冗长空闲时段。因此,一般认为游戏不断使用CPU是完全可以接受的。
根据您的要求,可能更高效的问题不是如何降低CPU利用率,以确保CPU利用率达到一个好的目的。通常,并发队列可以提供无锁,无阻塞的查询,以检查队列是否为空,您似乎已经给出了这一行:
while (a_queue.empty());
当队列为空时,你可能会偷偷摸摸地计算一些东西。通过这种方式,您不会仅仅忙于等待队列变为非空的循环。
同样,通常你的问题的理想答案将涉及一个条件变量(它取决于上下文切换和线程被唤醒)。它通常是让线程进入休眠状态(降低CPU利用率)并在所需时间唤醒的最快方法,但考虑到严格的延迟要求,最好忘记CPU利用率并更多地关注确保它达到了一个好的目的。
答案 2 :(得分:0)
std::queue
不是线程安全的。正如@Hurkyl发布的那样,如果您想使用std::queue
,则需要锁定。
按照编码,如果多个线程正在等待队列中的数据,他们可以所有对来自a_queue.fronf()
的相同值执行操作,然后多次调用a_queue.pop()
与队列中推送的值的数量无关。