C ++线程安全支架运算符代理

时间:2016-04-08 23:11:56

标签: c++ multithreading concurrency

给定标准向量的简单包装,为了能够像往常一样设置内容,以线程安全的方式实现operator[]的好方法是什么?

struct bracket_operator_proxy;

struct example
{
    auto operator[](size_t i) const { return bracket_operator_proxy(v, m, i); }
private:
    std::vector<double> v;
    std::mutex m;
};

以下是bracket_operator_proxy的快速而幼稚的尝试:

struct bracket_operator_proxy
{
     bracket_operator_proxy(std::vector<double>& v, std::mutex& m, int i)
        : v(v), m(m), i(i) {}

     operator double() const
     {
         std::lock_guard<std::mutex> l(m);
         return v[i];
     }

     auto operator=(double d)
     {
         std::lock_guard<std::mutex> l(m);
         v[i] = d;
         return d;
     }

     //... further assignment operators ...
private:
     std::vector<double>& v;
     std::mutex& m;
     int i;
};

这已经够了吗?或者我错过了会让我的腿脱落的东西?

1 个答案:

答案 0 :(得分:1)

一旦你有了operator->(这非常有用),你就需要返回一个->代理,它将锁定生命周期延长到语句结束,并使你暴露于单线程死锁。< / p>

查看线程安全的monads / functor / wrapper,如the one here。它不会使锁完全透明,但它们不应该

  • 不要在线程之间共享数据

  • 如果您共享数据,请将其设为不可变

  • 如果必须进行变异,请通过已知安全设计的瓶颈来隔离访问。消息队列说。

  • 如果您不能这样做,请考虑重新设计

  • 真。原子可能吗?

  • 拥有一组有限的功能来明确管理锁

  • 好的,现在如上所述包装读写器monad,使用简单的复合操作

  • 使代码神奇地获取锁定并且看起来就像非线程交互代码,从而使读者陷入虚假的安全感和效率感

降低偏好。

线程安全的危险和困难部分不是语法笨拙的事实。基于锁定的线程安全几乎不可能被证明是正确和安全的。使语法更容易使用并不是一个很有价值的目标。

例如,v[i]=v[i+1]充满了缺乏同步:在读取和写入之间,任何事情都可能发生变化。更不用说&#34; i是一个有效的索引?&#34;