另一个线程可以解锁互斥量,尽管它之前没有获得锁吗?

Can another tread unlock a mutex although it has not acquired the lock previously?

线程 t2 是否可以解锁互斥量 m,尽管该互斥量先前已被线程 t1 锁定?互斥量 m 可以解锁两次吗?

为了说明这些问题,我编写了以下小脚本:

#include <atomic>
#include <mutex>
#include <thread>
#include <iostream>

class spinlock_mutex {
    std::atomic_flag flag;

   public:
    spinlock_mutex() : flag(ATOMIC_FLAG_INIT){};
    void lock() {
        while (flag.test_and_set(std::memory_order_acquire)) {
            std::cout << "cloud not acquire lock" << std::endl;
        }
        std::cout << "acquired lock" << std::endl;
    }
    void unlock() {
        flag.clear(std::memory_order_release);
        std::cout << "release lock" << std::endl;
    }
};

int main() {
    spinlock_mutex mutex{};
    std::lock_guard<spinlock_mutex> lock_a(mutex);
    std::thread t2([&](){mutex.unlock();});
    t2.join();
    std::cout << "t2 has unlocked the mutex" << std::endl;
}

执行此代码会打印以下内容:

acquired lock
release lock
t2 has unlocked the mutex
release lock

在我看来,主线程是通过 lock_guard 工具获取互斥锁的。然后,线程 t2 解锁互斥体。在主范围的末尾,lock_guard 的析构函数再次解锁锁(现在不应该解锁吗?)。 (当我将自定义 spinlock_mutex 替换为 std::mutex 时,程序运行时没有任何投诉,但当然不会打印任何信息)。

所以我想知道线程t2是否真的可以解锁一个它没有锁定的互斥锁,最后主线程解锁了哪个互斥锁? cppreferenceunlock 函数的描述中警告未定义的行为,我想知道程序是否记录了这一点?

不,这是不允许的。

std::mutex::unlock

The mutex must be locked by the current thread of execution, otherwise, the behavior is undefined.

您分享的link已有答案

The mutex must be locked by the current thread of execution, otherwise, the behavior is undefined.

C++ 中的“未定义行为”并不意味着“程序可以定义它”。它的字面意思是“这种行为永远不会被任何符合标准的编译器定义”。有关术语的更多详细信息,请参阅 this question

具体来说,标准 (§32.5.4.2.1) 是这样说的

The expression m.unlock() is well-formed and has the following semantics:

Preconditions: The calling thread owns the mutex.

而 §16.3.2.4 将函数的前提条件定义为

Preconditions: the conditions that the function assumes to hold whenever it is called; violation of any preconditions results in undefined behavior.

所以在未定义的行为中解锁你不拥有的互斥量。它可以工作,它可以抛出异常,它可以忽略调用,它可以 summon demons out your nose.