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

Boost upgrade_lock and DCLP (double-checked locking pattern)

本文关键字:检查 锁定 模式 upgrade lock DCLP Boost      更新时间:2023-10-16

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

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. 一个线程获得独占访问,而另一个线程在标记为(!)的行处被挂起

我想第二种选择可能会发生,但在这种情况下,即使锁定了环境,我们也必须重新检查我们的数据是否在"外部"更改,即我们必须使用臭名昭著的DCLP。我说得对吗?

我还没有找到任何可信的信息,所以不要责怪我:)

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

如果您使用读写器锁,则必须遵守协议,该协议假定,只要多个读写器共享锁,它们就只能进行读取访问。如果他们需要获得一些写入权限,他们必须升级锁。

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

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

从这里你有多种选择:

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

选项2:只要再次调用delete,如果在调用delete之后指针被设置为NULLnullptr,C++就可以了(如果delete来自标准库)=>,并且什么都不做。仅供参考阅读:

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

如果表达式的计算结果为空指针值,则不会调用析构函数,也不会调用释放函数。

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

但是根据选项2,如果CCD_ 12由STL实现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()即可。