假设我们有以下(伪)代码:
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。我是对的吗?
我没有找到任何合理的信息,所以不要责怪我很多:)
答案 0 :(得分:0)
如果我正确理解你,那么数字2就会发生。
如果您使用的是Reader/Writer Locks,则必须坚持使用以下假定的协议:只要多个阅读器共享锁定,就只允许它们进行读取访问。如果他们需要获得一些写权限,他们必须升级锁。
现在,在您的情况下,可能会发生多个线程进入if
- 语句并等待锁获取。这是真的,他们将一个接一个地获得锁。问题是,在锁定获取之后,可能会发生另一个线程delete
- 表格。
这就是为什么你可能需要双重检查的锁定模式。
从这里你有多种选择:
选项1 :
检查表是否指向NULL
并且不执行任何操作
选项2 :
只需再次调用delete
,如果在调用NULL
后指针设置为nullptr
或delete
,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_ptr
或boost::shared_ptr
。他们是同步的。所以你甚至不需要锁,只需从多个线程调用ptr.reset()
即可。