5

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

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

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

为什么std::mutex::lock并且std::mutex::unlock是公开的?这需要不正确的用法:

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

将锁操作设为私有std::lock_guard并成为std::unique_lock其朋友不是更安全吗?这将防止不安全的使用。std::mutexstd::mutex

我能猜到这个设计的唯一原因是,如果我有自己的锁,它就不能使用,std::mutex因为我无法让自己的锁成为std::mutex. 这是公开这些成员函数的主要原因吗?

4

2 回答 2

13

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

与 boost 不同,互斥锁具有用于 lock()、unlock() 等的公共成员函数。这是支持主要目标之一所必需的:用户定义的互斥锁可以与标准定义的锁一起使用。如果用户定义的互斥锁没有接口来实现,那么标准定义的锁就无法与用户定义的互斥锁进行通信。

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

所以你现在可以写作my::mutex了,只要你提供会员lock()unlock()my::mutex就是一等公民std::mutex。您的客户可以像使用std::unique_lock<my::mutex>一样轻松使用std::unique_lock<std::mutex>,即使std::unique_lock不知道是什么my::mutex

现在在 C++1y (我们希望 y == 4)草案标准my::mutex中提出了一个鼓舞人心的现实生活示例。 拥有会员并为独占模式锁定和解锁。并且它与客户端按预期使用时进行交互。std::shared_mutexstd::shared_mutexlock()unlock()std::unique_lockstd::unique_lock<std::shared_mutex>

并且以防万一您可能认为shared_mutex可能是唯一可以使用此通用接口的其他激励互斥锁,这是另一个真实世界的示例::-)

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::mutexlock()unlock()

于 2013-11-04T03:21:52.880 回答
3

正如 Jerry Coffin 指出的那样,我们只能在没有实际委员会成员参与的情况下进行推测,但我的猜测是,他们设计的接口具有灵活性,并且能够以您自己的方式扩展它们。不是让每个潜在的类成为 的朋友,而是std::mutex公开接口以执行所需的操作,从而允许某人(例如 boost 贡献者)出现并找到一种新的更好的方法来做某事。如果界面是隐藏的,那是不可能的。

于 2013-11-04T03:22:52.843 回答