这是线程安全的Queue类的正确方法吗?

Pol*_*878 7 c++ concurrency multithreading thread-safety

我想知道这是否是在C++中编写线程安全队列的正确方法?

template <class T>
class Queue
{
public:

Queue() {}

void Push(T& a)
{
    m_mutex.lock();
    m_q.push_back(a);
    m_mutex.unlock();
}

T& Pop()
{
    m_mutex.lock();
    T& temp = m_q.pop();
    m_mutex.unlock();
    return temp;
}

private:
    std::queue<t> m_q;
    boost::mutex m_mutex;
};
Run Code Online (Sandbox Code Playgroud)

你明白了......我只是想知道这是不是最好的方法.谢谢!

编辑: 由于我得到的问题,我想澄清互斥量是一个boost :: mutex

Eli*_*ght 19

我建议使用Boost线程库来帮助您.

你的代码很好,除了你用C++编写代码时

some_mutex.lock();
// do something
some_mutex.unlock();
Run Code Online (Sandbox Code Playgroud)

然后,如果该// do something部分中的代码抛出异常,则永远不会释放锁.Boost库使用诸如lock_guard之类的类来解决这个问题,在该类中初始化一个在其构造函数中获取锁的对象,以及析构函数释放锁的对象.这样你就知道你的锁将永远被释放.其他语言通过try/finally语句实现此目的,但C++不支持此构造.

特别是,当您尝试从没有元素的队列中读取时会发生什么?这会引发异常吗?如果是这样,那么你的代码会遇到问题.

当试图获得第一个元素时,你可能想要检查是否存在某些东西,然后如果不存在就去睡觉并等到某个东西.这是一个条件对象的工作,也是由Boost库提供的,如果您愿意,可以在较低级别提供.

  • 非常明显的问题很好. (4认同)

gre*_*ade 8

Herb Sutter 去年在Dobbs Journal博士上写了一篇很好的文章,涵盖了线程安全,无锁,单生成器,单用户队列实现的所有主要问题.(对上个月发布的实施进行了更正.)

他在下一期的后续文章中针对多用户并发队列解决了一种更通用的方法,并对潜在的陷阱和性能问题进行了全面讨论.

还有一些关于类似并发主题的文章.

请享用.


Jam*_*lis 6

从线程角度来看,这看起来适合于简单的线程安全队列.

但是你有一个问题:std :: queue的pop()不会返回从队列中弹出的元素.你需要做的是:

T Pop()
{
    m_mutex.lock();
    T temp = m_q.front();
    m_q.pop();
    m_mutex.unlock();
    return temp;
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下,您不希望返回引用,因为引用的元素正从队列中弹出并被销毁.

你还需要有一些公共的Size()函数来告诉你队列中有多少元素(或者你需要优雅地处理调用Pop()并且队列中没有元素的情况) .

编辑: 虽然,正如Eli Courtwright指出的那样,你必须小心抛出异常的队列操作,并且使用Boost是一个好主意.