简体   繁体   English

是否有可能 2 个线程同时锁定一个互斥锁(使用互斥锁包装器)?

[英]Is it possible for 2 threads lock a mutex at the same time (use mutex wrapper)?

The question comes from an exmaple of std::condition_variable问题来自std::condition_variable 的一个例子

As far as I know, when I construct a new thread , it starts to execute immediately.据我所知,当我构造一个新thread ,它会立即开始执行。

So I wonder, would cv.wait(lk, []{return ready;});所以我想知道, cv.wait(lk, []{return ready;}); in worker_thread() , and std::lock_guard<std::mutex> lk(m);worker_thread()std::lock_guard<std::mutex> lk(m); in main , lock the mutex at the same time?main ,同时锁定互斥锁? Could this happen?这会发生吗?

(From cppreference I know that std::condition_variable::wait and std::lock_guard would lock the mutex during the construction.) (从 cppreference 我知道std::condition_variable::waitstd::lock_guard会在构造过程中锁定互斥锁。)

#include <iostream>
#include <string>
#include <thread>
#include <mutex>
#include <condition_variable>

std::mutex m;
std::condition_variable cv;
std::string data;
bool ready = false;
bool processed = false;

void worker_thread()
{
    // Wait until main() sends data
    std::unique_lock<std::mutex> lk(m);
    cv.wait(lk, []{return ready;});

    // after the wait, we own the lock.
    std::cout << "Worker thread is processing data\n";
    data += " after processing";

    // Send data back to main()
    processed = true;
    std::cout << "Worker thread signals data processing completed\n";

    // Manual unlocking is done before notifying, to avoid waking up
    // the waiting thread only to block again (see notify_one for details)
    lk.unlock();
    cv.notify_one();
}

int main()
{
    std::thread worker(worker_thread);

    data = "Example data";
    // send data to the worker thread
    {
        std::lock_guard<std::mutex> lk(m);
        ready = true;
        std::cout << "main() signals data ready for processing\n";
    }
    cv.notify_one();

    // wait for the worker
    {
        std::unique_lock<std::mutex> lk(m);
        cv.wait(lk, []{return processed;});
    }
    std::cout << "Back in main(), data = " << data << '\n';

    worker.join();
}

Mutex are meant to get a lock on resource, only 1 thread can get that lock.互斥锁旨在获取资源锁,只有 1 个线程可以获取该锁。 Locking of mutex is atomic, 2 threads cannot acquire a lock on mutex, if they can, then it defeats the purpose of mutex locks!互斥锁的锁定是原子性的,2 个线程无法获得互斥锁,如果可以,那就违背了互斥锁的目的!

Mutexes are built such that locking is an atomic operation: it will only complete on one thread at a time, regardless of how many threads are attempting to lock互斥体的构建使得锁定是一种原子操作:它一次只会在一个线程上完成,而不管有多少线程试图锁定

"Mutex" is a contraction of "mutual exclusion"; “互斥”是“互斥”的缩写; it's purpose is to allow only one thread to lock the mutex at any time.它的目的是在任何时候只允许一个线程锁定互斥锁。

That said, there's a serious problem in that example.也就是说,在那个例子中有一个严重的问题。 It has a potential deadlock, because it tries too hard to sequence inherently non-sequential operations.它有一个潜在的死锁,因为它试图对固有的非顺序操作进行排序。

The problem occurs if main goes through its locking code, sets ready to true , and calls notify() before the new thread locks the mutex and calls wait() .如果main其锁定代码,将ready设置为true ,并在新线程锁定互斥锁并调用wait()之前调用notify() ,则会出现问题。 If that happens, main will proceed to its call to wait() while the new thread is sitting in wait() , and neither one will notify the other one;如果发生这种情况, main将在新线程位于wait()时继续调用它的wait() ,并且两者都不会通知另一个; they're both waiting for the other one to do something.他们都在等待对方做点什么。

If you're unlucky, you won't see this when you're testing the code;如果你不走运,你在测试代码时不会看到这个; it might happen that the new thread starts to wait() before the main thread calls notify() , and then the code will work as expected.可能会发生新线程在主线程调用notify()之前开始wait() notify() ,然后代码将按预期工作。 That's unlucky because sooner or later it will lock up, most likely when you're demonstrating your code to your most important customer.这是不幸的,因为它迟早会锁定,最有可能是在您向最重要的客户展示您的代码时。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM