我创建了一个线程安全队列(参见代码)。该类似乎工作,但现在我想使组合front()和pop()线程安全,使线程首先获取元素,然后确保删除相同的元素。我可以提出一些解决方案,但它们对于用户方而言并不优雅,否则强大的异常安全保障将会丢失。
第一个解决方案是用户只需要锁定ThreadQueueu而不是调用front()和pop()并解锁ThreadQueue。但是,该类的整个想法是用户不必关心线程安全性。
第二个解决方案是将队列锁定在重载函数front()中,并仅在pop()中解锁。但是,在这种情况下,不允许用户只调用front()或pop(),而不是用户友好..
我提出的第三个选项是在类(frontPop)中创建一个公共函数,它返回前面的元素并将其删除。但是在这种情况下,异常安全性已经消失。
什么是用户友好(优雅)并保持异常安全的解决方案?
class ThreadQueue: private std::queue<std::string>
{
mutable std::mutex d_mutex;
public:
void pop()
{
lock_guard<mutex> lock(d_mutex);
pop();
}
std::string &front()
{
lock_guard<mutex> lock(d_mutex);
return front();
}
// All other functions
private:
};
答案 0 :(得分:4)
通常的解决方案是提供前后组合。 pop,接受存储弹出值的引用,如果弹出一个值,则返回bool
true
:
bool pop(std::string& t) {
lock_guard<mutex> lock(d_mutex);
if (std::queue<std::string>::empty()) {
return false;
}
t = std::move(std::queue<std::string>::front());
std::queue<std::string>::pop();
return true;
}
移动分配抛出的任何异常都发生在修改队列之前,维护值类型移动赋值运算符提供的异常保证。