我有class
(class A
)使用监控模式安全访问std::deque
。任何时候我需要简单地添加或删除元素我很好。
但有时候不同的class
(class B
)需要调用并获取deque
中class A
中元素的引用。
我一直在向该元素返回一个iterator
,但是另一个线程有可能将一个新元素“推送”到class A
并使class B
正在使用的迭代器无效。我可以考虑阻止这种情况的唯一方法是在返回mutex
之前锁定class A
iterator
,然后让class B
在完成释放时调用另一个函数mutex
,但这看起来很糟糕。
有什么想法更清洁吗?
答案 0 :(得分:2)
无论你如何处理它,都归结为使用std::mutex
来实现对对象和类成员的线程安全访问。
您可以使用std::mutex
足够长的时间来复制对象或类成员,并将副本返回给调用者,以便按照自己的意愿进行处理。
但是如果你不想制作共享类成员或对象的私有线程副本,那么这几乎是唯一的方法。这是非常基础的,各种高级线程安全库都在基础层面上完成了这一过程。
使用C ++ 11,可以使用lambdas实现一些语法糖。我们来看一个实现线程安全int
的简单案例:
class safe_int {
int n;
std::mutex m;
public:
template<typename functor_type>
void lock(functor_type &&functor)
{
std::unique_lock<std::mutex> lock(m);
functor(n);
}
};
然后,以线程安全的方式访问int
:
void do_something_with(safe_int *i)
{
i->lock([]
(int &n)
{
// Do something with 'n'. Use it. Set its value, whatever.
});
}
helper类方法获取互斥锁上的锁,并使用锁定的互斥锁调用lambda,将对私有的受互斥保护的类成员的引用传递给lambda。当lambda返回时,锁会自动释放。
继续前进,不再需要显式锁定和解锁互斥锁,只需调用lock()即可。线程安全由合同强制执行。
答案 1 :(得分:0)
我认为你的问题太过模糊,无法得到明确的答案。例如,一个答案可能是:只在shared_ptr
中存储deque
。但是你可能会争辩说,这对我来说并不好,因为它有一个额外的分配/间接&#34;或者它对你来说可能已经足够了。在回答您的问题之前,有很多关于您的用例的问题需要澄清。如:
deque
只包含常量值,或者说A
是唯一可以修改双端队列元素的对象,而B
只能读取从他们(这导致使用不同的锁,放到不同的地方)。 deque
?你能用另一个容器吗? (例如,参见this answer以获取标准关于关联容器迭代器的引用。)deque
(s)中存储的元素类型是什么?等...
一个简明的问题通常很好,但在这种情况下,更多的背景会有所帮助。