给定标准向量的简单包装,为了能够像往常一样设置内容,以线程安全的方式实现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;
};
这已经够了吗?或者我错过了会让我的腿脱落的东西?
答案 0 :(得分:1)
一旦你有了operator->
(这非常有用),你就需要返回一个->
代理,它将锁定生命周期延长到语句结束,并使你暴露于单线程死锁。< / p>
查看线程安全的monads / functor / wrapper,如the one here。它不会使锁完全透明,但它们不应该。
不要在线程之间共享数据
如果您共享数据,请将其设为不可变
如果必须进行变异,请通过已知安全设计的瓶颈来隔离访问。消息队列说。
如果您不能这样做,请考虑重新设计
真。原子可能吗?
拥有一组有限的功能来明确管理锁
好的,现在如上所述包装读写器monad,使用简单的复合操作
使代码神奇地获取锁定并且看起来就像非线程交互代码,从而使读者陷入虚假的安全感和效率感
降低偏好。
线程安全的危险和困难部分不是语法笨拙的事实。基于锁定的线程安全几乎不可能被证明是正确和安全的。使语法更容易使用并不是一个很有价值的目标。
例如,v[i]=v[i+1]
充满了缺乏同步:在读取和写入之间,任何事情都可能发生变化。更不用说&#34; i
是一个有效的索引?&#34;