C++11:为什么 std::condition_variable 使用 std::unique_lock?

2024-01-04

我对角色有点困惑std::unique_lock当与std::condition_variable。据我了解文档 http://en.cppreference.com/w/cpp/thread/unique_lock, std::unique_lock基本上是一个臃肿的锁防护,可以在两个锁之间交换状态。

到目前为止我已经用过pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)为此目的(我猜这就是 STL 在 posix 上使用的)。它需要一个互斥体,而不是一个锁。

这里有什么区别?事实是std::condition_variable处理std::unique_lock优化?如果是的话,具体如何更快?


那么没有技术原因吗?

我赞成 cmeerw 的回答,因为我相信他给出了技术原因。让我们来看看它。让我们假设委员会已决定condition_variable等待一个mutex。这是使用该设计的代码:

void foo()
{
    mut.lock();
    // mut locked by this thread here
    while (not_ready)
        cv.wait(mut);
    // mut locked by this thread here
    mut.unlock();
}

这正是一个不应该 use a condition_variable。在标有以下内容的区域:

// mut locked by this thread here

存在异常安全问题,而且很严重。如果在这些区域中抛出异常(或通过cv.wait本身),互斥锁的锁定状态就会泄漏,除非在某个地方也放置了 try/catch 来捕获异常并解锁它。但这只是您要求程序员编写的更多代码。

假设程序员知道如何编写异常安全代码,并且知道使用unique_lock来实现它。现在代码如下所示:

void foo()
{
    unique_lock<mutex> lk(mut);
    // mut locked by this thread here
    while (not_ready)
        cv.wait(*lk.mutex());
    // mut locked by this thread here
}

这已经好多了,但仍然不是一个很好的情况。这condition_variable接口让程序员不遗余力地让事情正常工作。如果出现以下情况,则可能存在空指针取消引用:lk意外地没有引用互斥体。并且没有办法condition_variable::wait检查该线程是否拥有锁mut.

哦,刚刚想起来,还有程序员可能选择错误的危险unique_lock公开互斥体的成员函数。*lk.release()这里将会是灾难性的。

现在我们来看看实际的代码是如何写的condition_variableAPI 需要一个unique_lock<mutex>:

void foo()
{
    unique_lock<mutex> lk(mut);
    // mut locked by this thread here
    while (not_ready)
        cv.wait(lk);
    // mut locked by this thread here
}
  1. 这段代码非常简单。
  2. 它是异常安全的。
  3. The wait函数可以检查lk.owns_lock()如果是则抛出异常false.

这些是推动 API 设计的技术原因condition_variable.

此外,condition_variable::wait不需要lock_guard<mutex>因为lock_guard<mutex>就是你所说的:我拥有这个互斥体的锁,直到lock_guard<mutex>破坏。但当你打电话时condition_variable::wait,您隐式释放互斥锁上的锁。所以这个动作不符合lock_guard用例/声明。

我们需要unique_lock无论如何,这样就可以从函数返回锁,将它们放入容器中,并以异常安全的方式锁定/解锁非作用域模式中的互斥体,所以unique_lock是自然的选择condition_variable::wait.

Update

竹子在下面的评论中建议我对比condition_variable_any,所以这里是:

问题:为什么不是condition_variable::wait模板化,以便我可以通过任何Lockable键入它?

Answer:

这是一个非常酷的功能。例如这张纸 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3427.html演示等待 a 的代码shared_lock(rwlock) 以共享模式对条件变量进行操作(这在 posix 世界中是闻所未闻的,但仍然非常有用)。然而,该功能的成本更高。

因此委员会引入了一种具有此功能的新类型:

`condition_variable_any`

有了这个condition_variable adaptor可以等待any可锁定类型。如果有会员的话lock() and unlock(), 你已准备好出发。正确实施condition_variable_any需要一个condition_variable数据成员和一个shared_ptr<mutex>数据成员。

因为这个新功能比你的基本功能更昂贵condition_variable::wait,并且因为condition_variable是一个如此低级的工具,这个非常有用但更昂贵的功能被放入一个单独的类中,这样您只需在使用它时付费。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++11:为什么 std::condition_variable 使用 std::unique_lock? 的相关文章

随机推荐

  • 比较日期以检查旧文件

    我想检查文件是否早于一定时间 例如 2 天 我设法以这种方式获取文件创建时间 gt gt gt import os path time gt gt gt fileCreation os path getctime filePath gt g
  • Spring Cloud AWS - 无效标头发布 SNS 通知

    我正在尝试使用org springframework cloud aws messaging core NotificationMessagingTemplate 来自 Spring Cloud AWS 将通知发布到 SNS 主题 每次发布
  • 易失性数组的替代方案

    从其他问题中 我了解到易失性数组的元素不是易失性的 只有引用本身是不稳定的 volatile int data Thread A data 4 457 Thread B System out println data 4 在这里 线程 B
  • Python 2.7:如何在 Windows 上将新行的分隔符限制为 '\n'?

    当我在 Windows 上运行的 python 2 7 脚本中写入文本文件时 新行分隔符是 r n 但我希望它是 n 我尝试过使用open http docs python org 2 library io html io open wit
  • iframe 用于嵌入 flash 内容时的 Webkit 字体渲染

    请参见http jsfiddle net CVwXV 2 http jsfiddle net CVwXV 2 如果您使用的是 Mac 当您在 Mac 上的 Chrome 或 Safari webkit 上查看此内容时 文本会跳至更浅的阴影
  • 根据outlook邮件更新excel表[关闭]

    很难说出这里问的是什么 这个问题是含糊的 模糊的 不完整的 过于宽泛的或修辞性的 无法以目前的形式得到合理的回答 如需帮助澄清此问题以便重新打开 访问帮助中心 help reopen questions 我的目标是每当我收到特定主题的邮件时
  • 如何使用另一个 python 脚本文件中的参数执行 python 脚本文件

    我的问题是我想使用另一个 python 文件中的参数执行一个 python 文件以获取返回的值 不知道我有没有解释清楚 example 从外壳我执行这个 getCameras py path to the scene 这会返回给我一个相机列
  • Celery 不注册任务

    你好 我刚刚开始将 Celery 与 Django 一起使用 我有一项需要定期执行的任务 在管理界面中 我可以在名为 任务 已注册 的下拉列表中看到我的任务 但是当 Celery Beat 尝试执行它时 会抛出 NotRegistered
  • 用 C# 编写“原始”HTTP 客户端

    我正在尝试用 C 编写一个 原始 HTTP 客户端 你可能会问为什么 我的目标是在 J2ME 中实现 HTTP 客户端 只能执行 GET 和有限的 POST 但首先我需要更好地理解 HTTP 协议 因此进行 C 尝试 我的第一次尝试失败了
  • 选择数据库后进行身份验证

    我的 MongoDB 服务器中有 3 个数据库 我正在使用 pymongo 用 Python3 编写一些脚本 我想使用最新的版本和做法 一旦我打开客户端并选择数据库 pymongo MongoClient mydatabase authen
  • 具有标题和项模板列的 Windows 8 XAML ListView 应具有相同的动态宽度

    我正在使用带有 Itemtemplate 和 Headertemplate 的 Listview 两个模板都包含 6 列 如果我为模板设置固定的列宽 一切都可以 如图一所示 但我想将项目的宽度设置为 自动 但后来我得到图 2 这要怎么处理呢
  • 创建组件实例并传递给另一个组件渲染为 [object HTMLelement]

    从我的组件 例如 Component 中 我尝试实例化一个 Angular 组件 例如 CustomComponent 设置一些属性 然后将其发送到表格 例如 CustomTable 进行渲染 但我不断收到 object HTMLEleme
  • Minio:使用 docker-compose 添加公共存储桶

    下面是我的 docker compose 中的一个服务 minio image minio minio edge environment MINIO ACCESS KEY minio123 MINIO SECRET KEY minio123
  • SQLite 中的“如果、那么、否则”

    在不使用自定义函数的情况下 SQLite 是否可以执行以下操作 我有两个表 它们通过通用 ID 号链接 在第二个表中 有两个变量 我想要做的是能够返回一个结果列表 其中包括 行 id 如果这两个变量的所有实例 可能有两个以上 均为 NULL
  • 如何中止 Python 脚本的执行? [复制]

    这个问题在这里已经有答案了 我有一个简单的 Python 脚本 如果满足条件 我想停止执行该脚本 例如 done True if done quit stop exit else do other stuff 本质上 我正在寻找与函数体中的
  • Google Books API 403 访问未配置

    我正在尝试联系 Google Books API 并执行书名搜索 这仅需要公共 API 密钥 不需要 OAUTH2 我得到的只是以下错误 error errors domain usageLimits reason accessNotCon
  • 替换 Android 中 Uri.Builder 中的查询参数?

    我传递一个 Uri Builder 对象作为子类的机制 以便在执行之前将任何必要的参数填充到 Uri 中Android 问题是 基类添加的参数之一使用builder appendQueryParameter q searchPhrase 需
  • 编辑注册表中的环境变量

    我想从注册表中读取所有环境变量 并在 Visual Studio 2010 Express 中使用 C 为其设置一个新值 因此我读取了本地机器的子项 SYSTEM CurrentControlSet Control Session Mana
  • 为通用递归程序生成递归树的程序

    通常 在解决递归或动态编程问题时 我发现自己会绘制递归树来帮助简化问题 然而 对于一些复杂的问题 我可以找到解决方案 但不知道如何绘制树 到目前为止我所尝试的是打印出调用函数及其参数 这在一些示例中证明是有用的 然而 我在这个答案中看到了m
  • C++11:为什么 std::condition_variable 使用 std::unique_lock?

    我对角色有点困惑std unique lock当与std condition variable 据我了解文档 http en cppreference com w cpp thread unique lock std unique lock