等待函数到底如何针对条件变量工作

2024-01-24

背景

我对条件变量如何与共享数据的并发访问结合使用的理解有些困惑。以下是描述我当前问题的伪代码。

// Thread 1: Producer
void cakeMaker()
{
    lock(some_lock);
    while(number_of_cakes == MAX_CAKES)
        wait(rack_has_space);

    number_of_cakes++;

    signal(rack_has_cakes);
    unlock(some_lock);
}

// Thread 2: Consumer
void cakeEater()
{
    lock(some_lock);
    while(number_of_cakes == 0)
        wait(rack_has_cakes);

    number_of_cakes--;

    signal(rack_has_space);
    unlock(some_lock);
}

让我们考虑以下场景:number_of_cakes为 0。因此,Thread 2被阻止在wait(rack_has_cakes). When Thread 1运行并增加number_of_cakes到 1,它发出信号rack_has_cakes。然而,Thread 2之前醒来Thread 1释放锁定some_lock,导致它重新进入睡眠状态并错过信号。

我不清楚操作wait and signal。它们是否像一个拨动开关,当signal被调用且为 0 时wait成功了吗?有人可以解释幕后发生的事情吗?

Question

有人可以引导我逐步完成上述代码的一次迭代,重点关注期间发生的事件吗?signal and wait方法调用?


线程2在线程1调用unlock(some_lock)之前醒来,所以它继续 再次进入睡眠状态,信号已丢失。

不,事情不是这样的。我将使用 C++std::condition_variable对于我的引用,但是 POSIX 线程以及互斥体和条件变量的大多数普通实现都以相同的方式工作。基本概念是相同的。

当线程 2 开始等待条件变量时,它已锁定互斥体。 wait() 操作解锁互斥体并等待条件变量原子地 http://en.cppreference.com/w/cpp/thread/condition_variable/wait:

原子地释放锁,阻塞当前正在执行的线程,并且 将其添加到等待 *this 的线程列表中。

该操作被认为是“原子的”;换句话说,不可分割。

然后,当条件变量发出信号时,线程重新锁定互斥体:

解锁时,无论什么原因,都会重新获取锁并等待 退出。

在另一个线程“调用解锁”之前,该线程不会“返回睡眠状态”。如果互斥量尚未解锁:当线程因条件变量的信号而唤醒时,线程将始终等待,直到再次成功锁定互斥量。这是无条件的。什么时候wait()返回互斥锁仍处于锁定状态。然后,也只有到那时,wait()函数返回。因此,事件的顺序是:

  1. 一个线程锁定互斥体,将某些计数器、变量或任何类型的互斥体保护数据设置为另一线程正在等待的状态。执行此操作后,线程向条件变量发出信号,然后在闲暇时解锁互斥体。

  2. 另一个线程已经在它之前锁定了互斥体wait()s 位于条件变量上。之一wait()的先决条件是互斥量必须在之前被锁定wait()链接的条件变量。因此,wait() 操作“原子地”解锁互斥锁。也就是说,互斥体解锁时不存在实例,并且线程尚未等待条件变量。什么时候wait()解锁互斥体,可以保证线程将等待,并且它将被唤醒。你可以把它带到银行。

  3. 一旦条件变量发出信号,wait()荷兰国际集团线程does not从返回wait()直到它可以重新锁定互斥锁。从条件变量接收到信号只是第一步,在最后一步中,线程必须再次锁定互斥锁。wait()手术。当然,这只发生在信号线程解锁互斥体之后。

当线程收到条件变量的信号时,它will从返回wait()。但不是立即,它必须等待,直到线程再次锁定互斥体,无论需要多长时间。它不会“回到睡眠状态”,而是等到再次锁定互斥锁,然后返回。您可以保证收到的条件变量信号将导致线程从wait(),并且互斥体将被线程重新锁定。而且由于原始的解锁然后等待操作是原子的,因此您可以保证收到条件变量信号。

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

等待函数到底如何针对条件变量工作 的相关文章

  • 为什么 C# Array.BinarySearch 这么快?

    我已经实施了一个很简单用于在整数数组中查找整数的 C 中的 binarySearch 实现 二分查找 static int binarySearch int arr int i int low 0 high arr Length 1 mid
  • 从Web API同步调用外部api

    我需要从我的 Web API 2 控制器调用外部 api 类似于此处的要求 使用 HttpClient 从 Web API 操作调用外部 HTTP 服务 https stackoverflow com questions 13222998
  • BitTorrent 追踪器宣布问题

    我花了一点业余时间编写 BitTorrent 客户端 主要是出于好奇 但部分是出于提高我的 C 技能的愿望 我一直在使用理论维基 http wiki theory org BitTorrentSpecification作为我的向导 我已经建
  • 用于登录 .NET 的堆栈跟踪

    我编写了一个 logger exceptionfactory 模块 它使用 System Diagnostics StackTrace 从调用方法及其声明类型中获取属性 但我注意到 如果我在 Visual Studio 之外以发布模式运行代
  • OleDbDataAdapter 未填充所有行

    嘿 我正在使用 DataAdapter 读取 Excel 文件并用该数据填充数据表 这是我的查询和连接字符串 private string Query SELECT FROM Sheet1 private string ConnectStr
  • 如何从 appsettings.json 文件中的对象数组读取值

    我的 appsettings json 文件 StudentBirthdays Anne 01 11 2000 Peter 29 07 2001 Jane 15 10 2001 John Not Mentioned 我有一个单独的配置类 p
  • 不同枚举类型的范围和可转换性

    在什么条件下可以从一种枚举类型转换为另一种枚举类型 让我们考虑以下代码 include
  • C++ OpenSSL 导出私钥

    到目前为止 我成功地使用了 SSL 但遇到了令人困惑的障碍 我生成了 RSA 密钥对 之前使用 PEM write bio RSAPrivateKey 来导出它们 然而 手册页声称该格式已经过时 实际上它看起来与通常的 PEM 格式不同 相
  • while 循环中的 scanf

    在这段代码中 scanf只工作一次 我究竟做错了什么 include
  • SolrNet连接说明

    为什么 SolrNet 连接的容器保持静态 这是一个非常大的错误 因为当我们在应用程序中向应用程序发送异步请求时 SolrNet 会表现异常 在 SolrNet 中如何避免这个问题 class P static void M string
  • 如何在整个 ASP .NET MVC 应用程序中需要授权

    我创建的应用程序中 除了启用登录的操作之外的每个操作都应该超出未登录用户的限制 我应该添加 Authorize 每个班级标题前的注释 像这儿 namespace WebApplication2 Controllers Authorize p
  • 控件的命名约定[重复]

    这个问题在这里已经有答案了 Microsoft 在其网站上提供了命名指南 here http msdn microsoft com en us library xzf533w0 VS 71 aspx 我还有 框架设计指南 一书 我找不到有关
  • Java执行器服务线程池[关闭]

    很难说出这里问的是什么 这个问题是含糊的 模糊的 不完整的 过于宽泛的或修辞性的 无法以目前的形式得到合理的回答 如需帮助澄清此问题以便重新打开 访问帮助中心 help reopen questions 如果我使用 Executor 框架在
  • 这些作业之间是否存在顺序点?

    以下代码中的两个赋值之间是否存在序列点 f f x 1 1 x 2 不 没有 在这种情况下 标准确实是含糊不清的 如果你想确认这一点 gcc 有这个非常酷的选项 Wsequence point在这种情况下 它会警告您该操作可能未定义
  • 向现有 TCP 和 UDP 代码添加 SSL 支持?

    这是我的问题 现在我有一个 Linux 服务器应用程序 使用 C gcc 编写 它与 Windows C 客户端应用程序 Visual Studio 9 Qt 4 5 进行通信 是什么very在不完全破坏现有协议的情况下向双方添加 SSL
  • 为什么编译时浮点计算可能不会得到与运行时计算相同的结果?

    In the speaker mentioned Compile time floating point calculations might not have the same results as runtime calculation
  • 如何将带有 IP 地址的连接字符串放入 web.config 文件中?

    我们当前在 web config 文件中使用以下连接字符串 add name DBConnectionString connectionString Data Source ourServer Initial Catalog ourDB P
  • 基于 OpenCV 边缘的物体检测 C++

    我有一个应用程序 我必须检测场景中某些项目的存在 这些项目可以旋转并稍微缩放 更大或更小 我尝试过使用关键点检测器 但它们不够快且不够准确 因此 我决定首先使用 Canny 或更快的边缘检测算法 检测模板和搜索区域中的边缘 然后匹配边缘以查
  • 哪种 C 数据类型可以表示 40 位二进制数?

    我需要表示一个40位的二进制数 应该使用哪种 C 数据类型来处理这个问题 如果您使用的是 C99 或 C11 兼容编译器 则使用int least64 t以获得最大的兼容性 或者 如果您想要无符号类型 uint least64 t 这些都定
  • F#:仅对第一个事件执行一次操作,没有可变性/锁定?

    我有这段代码 可以下载文件并在控制台中告诉我该文件有多大 use webClient new WebClient let lockObj new Object let mutable firstProgressEvent true let

随机推荐