手动解锁 RAII 包装器(如 st::unique_lock)的关联互斥量是否始终是 UB?
Is manually unlocking associated mutex of a RAII wrapper (like st::unique_lock) always a UB?
我想知道手动解锁与 RAII 包装器关联的互斥锁是否总是 UB。例如,如果我们在 RAII 包装器销毁 之前再次锁定它是否可以 像这样:
int i = 0;
std::mutex mx_;
void foo() {
for (int k = 0; k < 10000; k++) {
std::unique_lock<std::mutex> lk(mx_);
i++;
mx_.unlock();
mx_.lock();
i++;
}
}
我的问题的原因是我正在尝试编写一个小型 RAII 包装器,将共享锁升级为 std::shared_mutex
的独占锁,我需要手动 lock/unlock std::shared_mutex
与其他锁关联,我想知道它是否是 UB。这是我的 upgrade_lock
class:
template<typename Mutex>
class upgrade_lock {
public:
using mutex_type = Mutex;
explicit upgrade_lock(mutex_type& mx) : mxp_(&mx) {
mxp_->unlock_shared();
mxp_->lock();
}
~upgrade_lock() {
mxp_->unlock();
mxp_->lock_shared();
}
upgrade_lock(const upgrade_lock&) = delete;
upgrade_lock& operator=(const upgrade_lock&) = delete;
private:
mutex_type* mxp_ = nullptr;
};
我假设这个 class 仅在线程获取共享锁时使用。至于为什么 unlock/lock 对不被另一个互斥锁保护,我认为真的没有必要。我现在可以像这样使用 class:
int i = 0;
std::shared_mutex mx_;
void goo() {
for (int k = 0; k < 10000; k++) {
std::shared_lock<std::shared_mutex> lk(mx_);
if (i > 5000) {
upgrade_lock<std::shared_mutex> lk2(mx_);
i++;
}
}
}
如果你配对正确,我认为它不是 UB(并且不会出现异常,因为 @
DanielLangr 说,它会尝试解锁一个已经解锁的互斥体)
不过你可以直接传锁
template<typename lock_type>
class upgrade_lock {
public:
upgrade_lock(lock_type& src_lock):lock(&src_lock){
lock->unlock_shared();
lock->mutex()->lock();
}
~upgrade_lock() {
lock->mutex()->unlock();
lock->lock_shared();
}
upgrade_lock(const upgrade_lock&) = delete;
upgrade_lock& operator=(const upgrade_lock&) = delete;
private:
lock_type* lock;
};
(代码未经测试)
我想知道手动解锁与 RAII 包装器关联的互斥锁是否总是 UB。例如,如果我们在 RAII 包装器销毁 之前再次锁定它是否可以 像这样:
int i = 0;
std::mutex mx_;
void foo() {
for (int k = 0; k < 10000; k++) {
std::unique_lock<std::mutex> lk(mx_);
i++;
mx_.unlock();
mx_.lock();
i++;
}
}
我的问题的原因是我正在尝试编写一个小型 RAII 包装器,将共享锁升级为 std::shared_mutex
的独占锁,我需要手动 lock/unlock std::shared_mutex
与其他锁关联,我想知道它是否是 UB。这是我的 upgrade_lock
class:
template<typename Mutex>
class upgrade_lock {
public:
using mutex_type = Mutex;
explicit upgrade_lock(mutex_type& mx) : mxp_(&mx) {
mxp_->unlock_shared();
mxp_->lock();
}
~upgrade_lock() {
mxp_->unlock();
mxp_->lock_shared();
}
upgrade_lock(const upgrade_lock&) = delete;
upgrade_lock& operator=(const upgrade_lock&) = delete;
private:
mutex_type* mxp_ = nullptr;
};
我假设这个 class 仅在线程获取共享锁时使用。至于为什么 unlock/lock 对不被另一个互斥锁保护,我认为真的没有必要。我现在可以像这样使用 class:
int i = 0;
std::shared_mutex mx_;
void goo() {
for (int k = 0; k < 10000; k++) {
std::shared_lock<std::shared_mutex> lk(mx_);
if (i > 5000) {
upgrade_lock<std::shared_mutex> lk2(mx_);
i++;
}
}
}
如果你配对正确,我认为它不是 UB(并且不会出现异常,因为 @ DanielLangr 说,它会尝试解锁一个已经解锁的互斥体)
不过你可以直接传锁
template<typename lock_type>
class upgrade_lock {
public:
upgrade_lock(lock_type& src_lock):lock(&src_lock){
lock->unlock_shared();
lock->mutex()->lock();
}
~upgrade_lock() {
lock->mutex()->unlock();
lock->lock_shared();
}
upgrade_lock(const upgrade_lock&) = delete;
upgrade_lock& operator=(const upgrade_lock&) = delete;
private:
lock_type* lock;
};
(代码未经测试)