访问者中的QReadWriteLock

时间:2017-08-08 07:39:43

标签: qt concurrency qt4 mutex qreadwritelock

我有一个MyClass的QList。从列表中追加和删除项目很少见,并且由常用列表互斥锁控制。 MyClass包含几个子结构和个人QReadWriteLock:

MyClass{
private:
   Substructure substructure;
   QReadWriteLock rwlElem;
}

我把储物柜放在这样的加速器中:

Substructure MyClass::getSub(){
  QReadLocker lock(&rwlElem);
  return substructure;
}

我希望能够安全地返回子结构的副本。我在制作者中所做的一样。这是一个很好的做法,使用这样的储物柜?首先会发生什么:复制下部结构或破坏储物柜?

1 个答案:

答案 0 :(得分:0)

我首先回答你的上一个问题:

  

首先发生什么:复制子结构的构造或破坏储物柜?

TL; DR:复制构造在破坏所有局部变量之前发生。

此处已在stackoverflow上多次询问此问题,请参阅hereherehere

CWG 1885已将更精确的措辞应用于C ++ 14标准:

  

N4606§6.6.3[stmt.return] / 3

     

调用结果的复制初始化在由return语句的操作数建立的完整表达式结束时临时销毁之前被排序,然后,在销毁之前被排序包含return语句的块的局部变量(6.6)。

  

我有一个MyClass的QList。从列表中追加和删除项目很少见,并且由常用列表互斥锁控制。 MyClass包含几个子结构和个人QReadWriteLock

要锁定两个互斥锁会使您容易出现死锁。但是,您可以遵循以下两条准则之一来避免这种情况:

  • 避免嵌套锁,一次只能锁定一个互斥锁。在获得新锁之前,请确保释放当前持有的锁。
  • 如果您无法做到这一点,则必须始终以固定顺序获取锁,并且此顺序应在整个应用程序中保持一致(即始终锁定保护整个应用程序的互斥锁在需要同时锁定两个互斥锁时锁定特定MyClass实例的读/写互斥锁之前的列表。
  

我在制作者中所做的一样。这是一个很好的做法,使用这样的储物柜?

假设您在setter中使用了QWriteLocker,这应该没问题(从某种意义上说它不会导致未定义的行为)。但是你必须注意你的界面真正在说什么。例如,当您对类型为mc的实例MyClass执行此类操作时:

Substructure s = mc.getSub();
if(s == anotherSubstructure)
    mc.doSomething();

当执行上述代码的线程将sanotherSubstructure进行比较时,另一个线程可能会更改substructure内的实际mc,此更改不是' t对前一个线程可见(因为它有自己的substructure副本。)

关键是,当您执行Substructure s = mc.getSub();时,您唯一知道的是mc的子结构在某个时间点等于s < / strong>,一旦您在getSub函数中释放锁定,此值可能会更改。

在上面的例子中,doSomething()不能假设mc的子结构的值仍然等于anotherSubstructure。您可能需要在自己的函数中对需要原子化的操作进行分组(使用锁可以确保在上述情况下值不会发生变化)。