借用Howard Hinnant的例子并将其修改为使用copy-and-swap,这是op =线程安全吗?
struct A {
A() = default;
A(A const &x); // Assume implements correct locking and copying.
A& operator=(A x) {
std::lock_guard<std::mutex> lock_data (_mut);
using std::swap;
swap(_data, x._data);
return *this;
}
private:
mutable std::mutex _mut;
std::vector<double> _data;
};
Run Code Online (Sandbox Code Playgroud)
我相信这个线程安全(记住op =的参数是通过值传递的),我能找到的唯一问题是在地毯下扫描的那个:复制ctor.但是,它是一种罕见的类,它允许复制赋值而不是复制构造,因此在两种选择中都存在同样的问题.
鉴于自我分配是如此罕见(至少在这个例子中)我不介意额外的副本如果发生,考虑这个!=&rhs的潜在优化要么可以忽略不计,要么是悲观化.与原始策略(下面)相比,是否还有其他理由更喜欢或避免它?
A& operator=(A const &rhs) {
if (this != &rhs) {
std::unique_lock<std::mutex> lhs_lock( _mut, std::defer_lock);
std::unique_lock<std::mutex> rhs_lock(rhs._mut, std::defer_lock);
std::lock(lhs_lock, rhs_lock);
_data = rhs._data;
}
return *this;
}
Run Code Online (Sandbox Code Playgroud)
顺便说一句,我认为这简洁地处理了复制文件,至少在本课程中,即使它有点迟钝:
A(A const &x) : _data {(std::lock_guard<std::mutex>(x._mut), x._data)} {}
Run Code Online (Sandbox Code Playgroud) 我需要以这样一种方式实现(在C++中)线程安全容器,只有一个线程能够从容器中添加或删除项目.我之前通过在线程之间共享互斥锁来完成此类操作.这会导致很多互斥对象在我的代码中被乱丢,并且使得事情变得非常混乱并且难以维护.
我想知道是否有更整洁,更面向对象的方式来做到这一点.我想到了容器周围的以下简单类包装器(半伪C++代码)
class LockedList {
private:
std::list<MyClass> m_List;
public:
MutexObject Mutex;
};
Run Code Online (Sandbox Code Playgroud)
这样可以通过以下方式完成锁定
LockedList lockableList; //create instance
lockableList.Mutex.Lock(); // Lock object
... // search and add or remove items
lockableList.Mutex.Unlock(); // Unlock object
Run Code Online (Sandbox Code Playgroud)
所以我的问题是从设计的角度来看这是否是一个好的方法?我知道从设计的角度来看,允许公众访问成员是不受欢迎的,上述设计是否存在任何严重缺陷.如果是这样,有更好的方法来实现线程安全的容器对象?
我已经阅读了很多关于设计和C++的书籍,但似乎确实存在关于多线程编程和多线程软件设计的文献缺失.
如果以上是解决问题的一种不好的方法,我可以有人建议一种方法来改进它,或者指出一些信息,解释设计类是线程安全的好方法??? 非常感谢.