如何维护对另一个类中的元素的线程安全引用

时间:2015-08-28 23:08:53

标签: c++ multithreading c++11

我有classclass A)使用监控模式安全访问std::deque。任何时候我需要简单地添加或删除元素我很好。 但有时候不同的classclass B)需要调用并获取dequeclass A中元素的引用。

我一直在向该元素返回一个iterator,但是另一个线程有可能将一个新元素“推送”到class A并使class B正在使用的迭代器无效。我可以考虑阻止这种情况的唯一方法是在返回mutex之前锁定class A iterator,然后让class B在完成释放时调用另一个函数mutex,但这看起来很糟糕。

有什么想法更清洁吗?

2 个答案:

答案 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)中存储的元素类型是什么?
  • 此代码的预期数据大小和所需性能是多少?

等...

一个简明的问题通常很好,但在这种情况下,更多的背景会有所帮助。