提升upgrade_lock和DCLP(双重检查锁定模式)

时间:2017-11-13 12:08:40

标签: c++ multithreading boost locking double-checked-locking

假设我们有以下(伪)代码:

using UpgradeLock = boost::upgrade_lock<boost::shared_mutex>;
using UpgradeToUniqueLock = boost::upgrade_to_unique_lock<boost::shared_mutex>;

boost::shared_mutex mtx;

void DeleteTable(<tbl>) {
  UpgradeLock lock(mtx);
  if (<the table exists>) {
    UpgradeToUniqueLock up(lock); // (!)
    // delete the table
  }
}

假设两个线程刚刚进入此函数并且都到达了语句,标有(!)

我无法弄清楚接下来会发生什么。我有以下选择:

  1. 在第二个线程释放其UpgradeLock之前,一个线程无法获得独占访问权限,但在它获得独占访问权限之前不能获得。死锁。
  2. 一个主题获取独占访问权限,而另一个主题在标记为(!)的行中暂停。
  3. 我想第二个选项可能会发生,但在这种情况下它出来了,即使有锁定的环境,我们必须重新检查我们的数据没有“在外面”改变,即我们必须使用臭名昭着的DCLP。我是对的吗?

    我没有找到任何合理的信息,所以不要责怪我很多:)

1 个答案:

答案 0 :(得分:0)

如果我正确理解你,那么数字2就会发生。

如果您使用的是Reader/Writer Locks,则必须坚持使用以下假定的协议:只要多个阅读器共享锁定,就只允许它们进行读取访问。如果他们需要获得一些写权限,他们必须升级锁。

现在,在您的情况下,可能会发生多个线程进入if - 语句并等待锁获取。这是真的,他们将一个接一个地获得锁。问题是,在锁定获取之后,可能会发生另一个线程delete - 表格。

这就是为什么你可能需要双重检查的锁定模式。

从这里你有多种选择:

选项1 : 检查表是否指向NULL并且不执行任何操作

选项2 : 只需再次调用delete,如果在调用NULL后指针设置为nullptrdelete,C ++就可以了(如果delete来自标准lib)=&gt;并且什么都不做。仅供参考阅读:

http://en.cppreference.com/w/cpp/language/delete

  

如果expression求值为空指针值,则不调用析构函数,并且不调用释放函数。

  UpgradeLock lock(mtx);

  if (<the table exists>) 
  {
     UpgradeToUniqueLock up(lock); // (!)
     if(<table still exists>)
     {
       // delete the table
       // and set the pointer to nullptr
     }
   } 

但是根据选项2,如果STL实现delete,则以下代码段就可以了:       UpgradeLock锁定(mtx);

  if (<the table exists>) 
  {
     UpgradeToUniqueLock up(lock); // (!)   
     // delete the table
     // and set the pointer to nullptr

  } 

选项3 : 请改用std::shared_ptrboost::shared_ptr。他们是同步的。所以你甚至不需要锁,只需从多个线程调用ptr.reset()即可。