假设我们有以下(伪)代码:
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
}
}
假设两个线程刚刚进入这个函数并且都到达了语句,标记为(!)
。
我不知道接下来会发生什么。我有以下选择:
- 在第二个线程释放其
UpgradeLock
之前,一个线程无法获得独占访问权,但在它也获得独占访问权之前也无法获得独占访问权。死锁。 - 一个线程获得了独占访问权,而另一个线程在带有标记
(!)
的行处被挂起。
我想第二个选项可能会发生什么,但在这种情况下,即使有锁定的环境,我们也必须重新检查我们的数据没有被“外部”更改,即我们必须使用臭名昭著的 DCLP。我说得对吗?
我还没有找到任何关于它的合理信息,所以不要怪我太多:)
最佳答案
如果我理解正确,那么数字 2 将会发生。
如果您使用 Reader/Writer Locks您必须遵守假设的协议(protocol),只要多个读者共享锁,他们就只能进行读取访问。如果他们需要获得一些写权限,他们必须升级锁。
现在在你的情况下,可能会发生多个线程进入 if
语句并等待获取锁。没错,他们都会一个接一个地拿到锁。问题是,在获取锁之后,另一个线程可能已经删除了
表。
这就是您可能需要双重检查锁定模式的原因。
从这里您有多种选择:
选项 1:
检查表是否指向 NULL
并且什么都不做
选项 2:
如果在调用 delete
之后指针设置为 NULL
或 nullptr
,只需再次调用 delete
C++ 即可那(如果 delete
来自标准库)=> 什么都不做。仅供引用阅读:
http://en.cppreference.com/w/cpp/language/delete
if expression evaluates to a null pointer value, no destructors are called, and the deallocation function is not called.
UpgradeLock lock(mtx);
if (<the table exists>)
{
UpgradeToUniqueLock up(lock); // (!)
if(<table still exists>)
{
// delete the table
// and set the pointer to nullptr
}
}
但根据选项 2,如果 delete
由 STL 实现,则以下代码片段就可以了:
UpgradeLock 锁(mtx);
if (<the table exists>)
{
UpgradeToUniqueLock up(lock); // (!)
// delete the table
// and set the pointer to nullptr
}
选项 3:
请改用 std::shared_ptr
或 boost::shared_ptr
。它们是同步的。因此,您甚至不需要锁,只需从多个线程调用 ptr.reset()
即可。
关于c++ - boost upgrade_lock 和 DCLP(双重检查锁定模式),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47264045/