c++ - 保持 std::mutex 锁定/解锁公开的基本原理

标签 c++ multithreading c++11

我的问题很简单。在 C++11 中,我们有 std::mutexstd::lock_guardstd::unique_lock

通常使用这些类的方法是通过任何锁来锁定std::mutex。这可以防止由于异常抛出而导致的互斥锁泄漏:

{
   std::lock_guard<std::mutex> l(some_mutex);
   //Cannot leak mutex.
}

为什么 std::mutex::lockstd::mutex::unlock 是公开的?这要求不正确的用法:

{ 
     some_mutex.lock();
     //Mutex leaked due to exception.
     some_mutex.unlock();
}

std::lock_guardstd::unique_lock 成为 std::mutex 的 friend 并让 std::mutex 锁定操作私有(private)?这将防止不安全的使用。

对于这种设计,我能猜到的唯一原因是,如果我有自己的锁,它就不能与 std::mutex 一起使用,因为我无法制作自己的锁锁定 std::mutex 的友元。这是公开这些成员函数的主要原因吗?

最佳答案

此设计决策的基本原理记录在 N2406 中:

Unlike boost, the mutexes have public member functions for lock(), unlock(), etc. This is necessary to support one of the primary goals: User defined mutexes can be used with standard defined locks. If there were no interface for the user defined mutex to implement, there would be no way for a standard defined lock to communicate with the user defined mutex.

在撰写本文时,boost::mutex 只能通过 boost::scoped_lock 锁定和解锁。

所以你现在可以写my::mutex ,只要你供应成员(member)lock()unlock() , 你的 my::mutexstd::mutex一样是一等公民.您的客户可以使用 std::unique_lock<my::mutex>就像他们可以使用一样容易 std::unique_lock<std::mutex> , 即使 std::unique_lock不知道是什么my::mutex是。

my::mutex 的激励性现实生活示例是提议std::shared_mutex现在在 C++1y 中(我们希望 y == 4)draft standard . std::shared_mutex有成员lock()unlock()用于独占模式锁定和解锁。它与 std::unique_lock 交互当客户端使用 std::unique_lock<std::shared_mutex>正如预期的那样。

以防万一你可能相信shared_mutex可能是唯一可以使用这个通用接口(interface)的其他激励互斥体,这是另一个真实世界的例子::-)

template <class L0, class L1>
void
lock(L0& l0, L1& l1)
{
    while (true)
    {
        {
            unique_lock<L0> u0(l0);
            if (l1.try_lock())
            {
                u0.release();
                break;
            }
        }
        this_thread::yield();
        {
            unique_lock<L1> u1(l1);
            if (l0.try_lock())
            {
                u1.release();
                break;
            }
        }
        this_thread::yield();
    }
}

这是关于如何同时锁定(以异常安全的方式)两个 BasicLockables 而没有死锁危险的基本代码。尽管有许多相反的批评,但这段代码非常高效。

注意上面代码中的一行:

            unique_lock<L0> u0(l0);

这个算法不知道什么类型L0是。但是只要支持lock()unlock() (好的,try_lock() 也是),一切都很酷。 L0甚至可能是 unique_lock 的另一个实例, 也许 unique_lock<my::mutex>甚至 unique_lock<std::shared_mutex> ,甚至可能是 std::shared_lock<std::shared_mutex> .

一切正常。都是因为std::unique_lock之间没有亲密关系和 std::mutex除了商定的公共(public)接口(interface) lock()unlock() .

关于c++ - 保持 std::mutex 锁定/解锁公开的基本原理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19761011/

相关文章:

c - 使用线程和互斥锁来搜索目录

c++ - Qt 多线程 QObject 单例

c++ - 将 const std::unique_ptr 用于 pimpl 习惯用法

c++ - 检测模板方法和自由函数的存在

django - 在线程中使用 Django ORM 并通过使用 BoundedSemaphore 避免 "too many clients"异常

c++ - C++11 中::new 的线程安全

c++ - 我在这个 C++ FreeType GLFW 应用程序的编译/链接阶段缺少什么?

c++ - 我如何优化以下程序?

c++ - 有什么方法可以禁用特定代码行的编译器优化?

c# - 根据程序内存查找新地址