Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/130.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 具有不可复制boost::mutex的类的赋值运算符_C++_Multithreading_Boost Thread - Fatal编程技术网

C++ 具有不可复制boost::mutex的类的赋值运算符

C++ 具有不可复制boost::mutex的类的赋值运算符,c++,multithreading,boost-thread,C++,Multithreading,Boost Thread,我在这里阅读了这篇老文章,其中有一条指导原则,可以为具有boost::mutex不可复制对象作为成员的类实现复制构造和赋值操作符 我对复制构造函数很满意,但对赋值运算符有一些疑问。 下面的说明仍然有效吗 // old boost thread const counter & operator=( const counter& other ){ if (this == &other) return *this; boos

我在这里阅读了这篇老文章,其中有一条指导原则,可以为具有
boost::mutex
不可复制对象作为成员的类实现复制构造和赋值操作符

我对复制构造函数很满意,但对赋值运算符有一些疑问。 下面的说明仍然有效吗

  // old boost thread    
  const counter & operator=( const counter& other ){
     if (this == &other)
        return *this;

     boost::mutex::scoped_lock lock1(&m_mutex < &other.m_mutex ?
                                        m_mutex : other.m_mutex);
     boost::mutex::scoped_lock lock2(&m_mutex > &other.m_mutex ?
                                        m_mutex : other.m_mutex);
     m_value = other.m_value;

     return *this;
}
//旧的boost线程
常量计数器和运算符=(常量计数器和其他){
如果(此==&其他)
归还*这个;
boost::mutex::作用域锁定锁1(&m\u mutex<&other.m\u mutex?
m_mutex:other.m_mutex);
boost::mutex::作用域锁定锁2(&m\u mutex>&other.m\u mutex)?
m_mutex:other.m_mutex);
m_值=其他m_值;
归还*这个;
}
是否应将其更新为:

 // new boost thread    
 const counter& operator=(const counter& other){
    if (this == &other)
       return *this;

    boost::unique_lock<boost::mutex> l1(m_mutex, boost::defer_lock);
    boost::unique_lock<boost::mutex> l2(other.m_mutex, boost::defer_lock);
    boost::lock(l1,l2);
    m_value = other.m_value;

    return *this;
}
//新的boost线程
常量计数器和运算符=(常量计数器和其他){
如果(此==&其他)
归还*这个;
boost::unique_lock l1(m_互斥体,boost::defer_lock);
boost::unique_lock l2(other.m_mutex,boost::defer_lock);
boost::锁(l1,l2);
m_值=其他m_值;
归还*这个;
}

首先,我假设问题在于锁定多个任意互斥锁时避免死锁。重要的是在使用一组互斥体的代码中始终使用相同的排序约定。如果可以保证互斥锁A总是在B之前锁定,B总是在C之前锁定,A总是在C之前锁定,那么就可以避免死锁

在第一个代码示例中,约定是首先用较低的内存地址锁定互斥锁。这将很好地工作,因为地址顺序是不变的。第二个版本是避免死锁的方法。本文档未指定内部执行的排序。我不建议在源代码中查找它,并在代码的其他地方使用这些信息——如果库发生更改,它可能会微妙地破坏一些东西

如果您是从零开始的(您以前在代码中一次没有持有多个互斥对象),那么使用Boost的方法肯定更可取——您不必担心确切的顺序,只要每次都让Boost决定。如果代码的其余部分使用内存排序,则必须使用内存排序。如果您的代码完全使用了其他约定,那么您也需要在这里应用这些约定。在任何情况下,您都不应该在可能同时持有的任何一组锁中混合约定,这只是自找麻烦

回答评论中的问题:


自定义锁排序方案在某些情况下非常有用,特别是当您需要长时间持有某些锁(A),但某些锁(B)仅短暂持有,而持有较长的锁时。例如,如果需要在类型A的对象上运行长作业,这会短暂地影响B的许多实例。惯例是始终先获取A的锁,然后获取B对象上的锁:

void doStuff(A& a, std::list<B*> bs) { boost::unique_lock<boost::mutex> la(a.mutex); // lock a throughout for (std::list<B*>::iterator ib = bs.begin(); ib != bs.end(); ++ib) { // lock each B only for one loop iteration boost::unique_lock<boost::mutex> lb(ib->mutex); // work on a and *ib // ... } } 无效数据集(A&A,标准::列表bs) { boost::unique_lock la(a.mutex);//锁定a for(std::list::迭代器ib=bs.begin();ib!=bs.end();++ib) { //仅为一次循环迭代锁定每个B boost::unique_lock lb(ib->mutex); //在a和*ib上工作 // ... } } 您可能能够在每次循环迭代之间放弃锁,并使用Boost的/C++0x的锁顺序,但这取决于doStuff()的作用,这可能会使算法更加复杂或混乱


另一个例子:在运行时环境中,对象不一定保持在相同的内存位置(例如,由于复制垃圾收集),依赖内存地址进行排序是不可靠的。因此,您可以给每个对象一个唯一的ID,并根据ID顺序确定锁的顺序。

我只想指出,从技术上讲,FAQ中给出的解决方案并不总是有效的。比较这样的指针是未指定的,并且对于这两种比较都很可能产生
true
false
。正确的方法是对
void*
boost::mutex*
使用
std::less
(和kin)的专门化,因为函数比较函子在所有指针专门化上产生总的顺序。(您仍然不能保证有一个特定的结果,但可以保证有一个有效的顺序。)正确。这是针对死锁的。除了boost::lock或内存排序之外,我无法找出其他“排序约定”或方案。你有我可以看的例子吗?旁注:它不仅是boost方法,而且是使用std::lock(l1,l2)的C++0x方法。我同意你的观点。最好不要深入细节。自定义锁排序方案在某些情况下可能很有用,特别是当你需要长时间持有某些锁(A),但某些锁(B)仅在持有长锁时短暂持有。例如,如果您需要在类型A的对象上运行长作业,这会短暂地影响B的许多实例。约定总是先获取A的锁,然后获取B对象上的锁:自定义排序约定的示例对于注释来说太长,所以我把它添加到了答案中。有趣的例子和解释。非常感谢你抽出时间。祝您今天过得愉快。AFG