防止一段代码在协程中同时执行

2023-12-13

我需要保护一段代码免于在协程​​中同时执行。防止多线程环境中的并发执行很简单,只需使用std::lock_guard类模板。然而,我的协程是从单个线程调用的,因此该解决方案不适用。

以下是我想要完成的(伪)代码:

future<http_response> send_req_async(http_request req) {
    while (true) {
        // Attempt to send an HTTP request
        auto const& access_token{ token_store::access_token() };
        auto const response{ co_await impl::send_req_async(req, access_token) };
        if (response.status_code() == http_code::ok) {
            co_return response;
        }

        // Attempt to refresh access token
        if (response.status_code() == http_code::unauthorized) {
            // The following scope needs to be guarded against concurrent execution.
            // To guard against concurrent execution from multiple threads I would use:
            // lock_guard<mutex> guard(refresh_token_mutex);
            if (access_token != token_store::access_token()) {
                continue;
            }
            auto const& token{ co_await refresh_token(token_store::refresh_token()) };
            token_store::save_access_token(token);
            // End of section that needs to be guarded.
        }
    }
}

该代码旨在允许并行发出多个请求,同时仅允许尝试刷新过期访问令牌的单个协程调用。理想情况下,解决方案应该在令牌刷新操作正在进行时暂停并发协程调用,并在之后自动恢复(即与std::lock_guard在多线程环境中)。

协程机制或 C++ 标准库中是否内置了任何东西,可以让我以干净的方式实现这一点,还是我必须自己推出?


注意:我使用的是 Visual Studio 2017 15.7.2,因此您可以假设完全支持 C++17 及其 Coroutine TS 实现。


C++ 或标准库没有提供任何基础设施来获取所需的功能。但是,那协程TS提供构建块来实现co_await-able 异步互斥体。

总体思路是实现一个等待,在评估时尝试获取合适的互斥体await_suspend表达。如果无法获取锁,则协程将被挂起并添加到等待者队列中,否则立即继续执行(保持锁)。

互斥体'unlock方法从队列中恢复等待者,除非等待者队列为空。

网络上有预先构建的解决方案。我和刘易斯·贝克一起去了async_mutex实施的原因有很多:

  • 没有外部或内部依赖。只需将编译单元和头文件放入您的项目中即可完成。
  • 锁由协程拥有,而不是线程拥有。该实现允许协程在不同的线程上恢复。
  • 这是一个无锁的实现。

该实现的使用与std::lock_guard:

#include <cppcoro/async_mutex.hpp>

namespace {
    cppcoro::async_mutex refresh_mutex;
}

future<http_response> send_req_async(http_request req) {
    while (true) {
        // Attempt to send an HTTP request
        auto const& access_token{ token_store::access_token() };
        auto const response{ co_await impl::send_req_async(req, access_token) };
        if (response.status_code() == http_code::ok) {
            co_return response;
        }

        // Attempt to refresh access token
        if (response.status_code() == http_code::unauthorized) {
            // The following scope needs to be guarded against concurrent execution.
            auto const refresh_guard{ co_await refresh_mutex.scoped_lock_async() };
            if (access_token != token_store::access_token()) {
                continue;
            }
            auto const& token{ co_await refresh_token(token_store::refresh_token()) };
            token_store::save_access_token(token);
            // refresh_guard falls out of scope, unlocking the mutex.
            // If there are any suspended coroutines, the oldest one gets resumed.
        }
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

防止一段代码在协程中同时执行 的相关文章

  • 如何使用C从http下载文件?

    最近几天我试图弄清楚如何从 URL 下载文件 这是我对套接字的第一个挑战 我用它来了解协议 所以我想在没有 cURL 库的情况下只用 C 语言来完成它 我搜索了很多 现在我可以打印页面的源代码 但我认为这与文件不同 我不必只将接收到的数据从
  • 与 MinGW 的静态和动态/共享链接

    我想从一个简单的链接用法开始来解释我的问题 假设有一个图书馆z它可以编译为共享库 libz dll D libs z shared libz dll 或静态库 libz a D libs z static libz a 让我想要链接它 然后
  • 如何使用不同的基本路径托管 Blazor WebAssembly 应用程序

    我有一个 Blazor Webassemble NET 托管应用程序 在我们托管它的服务器上 应用程序的基本路径将是mydomain com coolapp 因此 为了尝试让应用程序在服务器上正确呈现 我一直遵循本页 应用程序基本路径 部分
  • 并行运行多个任务

    我有一个代理列表 每个代理都会访问不同的站点并从站点中提取所需的数据 目前它一次只做一个 但我希望同时运行 10 20 个任务 这样它就可以一次性从 20 个站点下载 而不是只下载一个 这是我目前正在做的事情 private async T
  • 从结构调用 C++ 成员函数指针

    我找到了有关调用 C 成员函数指针和调用结构中的指针的信息 但我需要调用结构内部存在的成员函数指针 但我无法获得正确的语法 我在类 MyClass 的方法中有以下代码片段 void MyClass run struct int MyClas
  • 如何以编程方式删除受信任的根证书颁发机构中的证书?

    我需要能够从组织中的每台电脑中删除特定的证书 是的 我可以逐个座位 但我要到周四才能完成 而且我没有人力逐个座位 是否有使用 C 的编程方式来执行此操作 我认为你不需要编写任何 C 看看certmgr exe del http msdn m
  • 我担心我添加了太多接口

    我正在构建我的领域模型并继续重构它 正如我所做的那样 我发现我喜欢接口 因为它允许我根据接口为具体类型创建可重用的方法 控制器 视图 但是 我发现每次向域实体之一添加新属性时 我都会创建一个接口 例如 我有一个会员状态从抽象继承的对象Ent
  • 在 C# 中解析 JS Date.toIsoString

    我需要将 JS 日期存储为 ISO 8601 日期 我目前正在从格式为 2019 06 22T00 00 00 000Z 的表单中获取日期 正如 JS 的 toIsoString 方法所期望的那样 当这个日期传递到我的 API 控制器时 我
  • C# 结构默认值

    我有一个方法 它接受一个包含许多具有基本数据类型的字段的结构 我想传递大部分默认值 但需要进行一些调整 但我了解结构声明中的基本字段不能包含默认值声明 例如struct S int a 42 现在是这样的 OptionsStruct opt
  • 加载 QPixmap 数据的更好方法

    更好的方法来做到这一点 没有QImage QImage image width height QImage Format RGB888 memcpy image bits m frameRGB gt data 0 height width
  • 为什么连续抛出 2 个异常不会生成无法访问的代码警告?

    为什么以下代码行不会创建编译器警告 void Main throw new Exception throw new Exception 据我所知 编译器应该通知您无法到达第二个抛出异常 这显然是一个编译器错误 它是在 C 3 0 中引入的
  • C# 可以为控制台应用程序部分类“程序”类吗?

    我想知道是否可以将为任何控制台应用程序创建的默认 程序 类更改为部分类 我想这样做是因为我想要更好的组织 而不是将所有方法都放在按区域分类的 1 个文件中 对我来说 将某些方法类别放在单独的文件中会更有意义 我对分部类的理解是 它是多个文件
  • main.cpp 是必需的吗?

    我试图编译一个程序cmake 我最终删除了我的main cpp文件 我刚刚将其复合到另一个包含我的项目名称的文件中 即 我刚刚将主函数剪切并粘贴到该文件中 问题是我有一个main cpp未发现错误 不确定是否在C 一个名为main cpp是
  • 运行实体框架自定义工具,它有什么作用?

    在 Visual Studio 中 当使用实体框架并为 tt 和 Context tt 文件应用运行自定义工具时 它是什么以及它有什么作用 为什么它解决数据库同步问题 有时 为什么我应该在运行 tt 之前运行它 Context tt 它被称
  • 如何在VS2005中使用从.bat而不是.exe启动的外部程序进行调试?

    在我的 c 项目的调试属性中 我选择了 启动外部程序 并选择了我希望将调试器附加到的程序的 exe 但是 现在我需要从 bat 文件而不是 exe 启动程序 但 VS2005 似乎不允许这样做 这可能吗 编辑 为了澄清 我需要调试从 bat
  • MPI - 发送和接收列

    我需要从一个进程发送矩阵列并从另一个进程接收它 我尝试运行以下程序 但得到了一个奇怪的结果 至少我这么认为 仅复制矩阵的第一个元素 某些矩阵元素会发生意外变化 include
  • 从单应性估计 R/T

    我一直在尝试计算 2 个图像中的特征 然后将这些特征传递回CameraParams R没有运气 特征已成功计算并匹配 但是问题是将它们传递回R t 我明白你必须分解Homography为了使这一点成为可能 我已经使用如下方法完成了 http
  • Windows Phone 的 JSON 反序列化

    我正在尝试反序列化以下 JSON 但我真的不知道如何使用 JSON net 来完成这项工作 我正在使用 C 和 JSON Net 库 我的 JSON 如下 found 3 bounds 43 54919 172 62148 43 54487
  • 稀疏矩阵超定线性方程组c/c++库

    我需要一个库来解决 Ax b 系统 其中 A 是一个非对称稀疏矩阵 每行有 8 个条目 而且可能很大 我认为实现双共轭梯度的库应该没问题 但我找不到一个有效的库 我尝试过 iml 但 iml sparselib 包中缺少一些标头 有小费吗
  • 如何使用 Microsoft Graph API 更新 MailboxSettings

    我想从不同的日历更新邮箱设置 如何构建可以通过 Microsoft Graph 更新 MailboxSetting 的请求 这是我的代码示例 但有例外 代码示例 User obj GraphServiceClient Users roomC

随机推荐

  • Toast 通知不起作用

    下面的方法在调用设置 Toast 时执行 但在经过一段时间后不会显示任何 Toast Windows 8 Metro 应用程序 Toast 通知是否还需要任何设置 int scheduledToastCounter 1 public voi
  • 为什么 R 和 statsmodels 给出的方差分析结果略有不同?

    使用小型 R 样本数据集和来自的 ANOVA 示例统计模型 其中一个变量的自由度报告不同 F 值结果也略有不同 也许他们的默认方法略有不同 我可以设置 statsmodels 以使用 R 的默认值吗 import pandas as pd
  • 如何将 wav 文件转换为类似字节的对象?

    我正在尝试使用 Python 3 5 1 的 audioop 模块以编程方式分析 wav 文件以获取通道 持续时间 采样率 音量等 但是我找不到任何文档来描述如何将 wav 文件转换为 片段 参数它必须是一个类似字节的对象 有人可以帮忙吗
  • 如何从oracle数据库中删除名为“BIN$c+eOnMB3RbKSEfg/rsxtAQ==$0”的奇怪表?

    我是 Oracle 新手 为了练习 我在 Oracle 11g 及更高版本中创建了一些表 客户 司机 付款 预订 位置 区域 工作 job history select from cat语句我发现一个奇怪的表 其中包含其他创建的名为 BIN
  • TSQL 生成 5 个字符长度的字符串,所有数字 [0-9] 数据库中尚不存在

    最好的方法是什么 我需要生成一个 5 位长度的字符串 其中所有字符都是数字 但是 我需要能够执行此 x 次 用户变量 并将此随机字符串存储在数据库中 此外 我无法两次生成相同的字符串 旧琴弦将在 6 个月后被移除 伪代码 DECLARE i
  • django - 启动 dbshel​​l sqlite3 时选项太多

    我有 django 1 2 3 0 Final 我正在使用 Python 2 7 在我的设置中 我为 DATABASE ENGINE 填充了 sqlite3 我能够使用 sqlite3 在 djano manage py shell 级别
  • 为什么 Powershell 的 Tee-Object 会搞乱我的文件编码?

    周末我使用 Tee Object 生成我跟踪的日志文件的一些输出 我尝试 grep 输出文件 但无法返回任何结果 但我能够 grep 原始日志文件 Tee Object 似乎更改了文件的编码 https adamtheautomator c
  • weblogic中的类强制转换异常

    我有一个使用球衣罐子的Web应用程序 WAR文件 现在 当我尝试部署这个时 我收到类转换异常 某些引导servlet使用球衣 在分析中 我发现weblogic本身有共同的球衣罐子 模块 和我的网络应用程序有不同版本的球衣罐 现在 如果我删除
  • iPhone 4 有没有绝对确定的方法可以让 NSTimer 长期火起来

    我的 NSTimers 和后台选择器一直遇到问题 这让我抓狂 并且需要很长时间来尝试每一个调整 为了保持我的理智以及未来几代可可程序员的理智 我问这个问题 是否有绝对 100 确定的方法可以在稍后的时间点触发预定的长期计时器 无论它是否是从
  • CMake:为 #cmakedefine 变量设置不同的名称

    我知道你可以使用 CMakeconfigure file使 CMake 变量可用于您的程序 例如 我可以使用 define CMAKE BUILD TYPE 导致 define Release 但是 为了使我的代码更具可读性 我更愿意定义
  • 重定向到 https 但没有 .php

    现在我有一个https 我需要在 htaccess 中进行重定向 我可以找到这个 RewriteCond HTTPS off RewriteRule https HTTP HOST REQUEST URI L R 301 但我发现如果用户写
  • Google Script CacheService 在 sendMail 中为 inlineImages 缓存图像

    我想将图像存储在 Google Script 的缓存服务中 然后将此图像作为内联图像插入 HTML 邮件中 我已经尝试让它发挥作用 但到目前为止还没有成功 记录器中以下代码的错误是 无效参数 附件 如果我检查它显示 sendMail 中的
  • 如何动态新的匿名类?

    在 C 3 0 中 您可以使用以下语法创建匿名类 var o1 new Id 1 Name Foo 有没有办法动态创建这些匿名类到变量 Example var o1 new Id 1 Name Foo var o2 new SQ 2 Bir
  • 在一个查询 MYSQL 中插入和更新

    我有一个简单的 INSERT 查询 在单击按钮的事件上运行 这会获取变量并将它们插入到order table 我也想更新我的bands表将库存减少 1 直到达到 0 然后显示空或已售完 而不是变为负数 例如 6 要知道选择了什么频段 我可以
  • Android逐字符显示文字动画

    任何人都知道执行动画的任何有效方法 所要做的就是逐个字符地显示文本 喜欢 T Th Thi This This i This is 等等 Thanks 这可能不是最优雅的解决方案 但最简单的可能是一个快速子类TextView with a
  • XSL 在 CDATA 中取消转义 HTML

    我正在尝试转换 XML
  • WebDriver 模拟桌面浏览器中的触摸事件

    我正在尝试使用 Chrome 和 Firefox 浏览器在基于 Web 的应用程序中模拟一些触摸事件 例如交换 点击 我尝试用以下方法模拟触摸事件Actions Hammer js Yahoo lib YUI 但它们都不适合我 在桌面浏览器
  • Django:CSV模型导入[重复]

    这个问题在这里已经有答案了 我需要一种将数据简历导入数据库的方法 csv 在字段方面与我的模型之一匹配 在 Django 中 有没有推荐的方法 包来做这样的事情 我查看了此处的 django csvimport http pypi pyth
  • 使用 jQuery select2 设置多个值[重复]

    这个问题在这里已经有答案了 我使用 jQuery select2 选择多个列表项 但不幸的是 下面的代码必须将所有 3 个值加载到选择字段中 但是它只加载第一个项目 如何将所有 3 个项目加载到 select2 列表中
  • 防止一段代码在协程中同时执行

    我需要保护一段代码免于在协程 中同时执行 防止多线程环境中的并发执行很简单 只需使用std lock guard类模板 然而 我的协程是从单个线程调用的 因此该解决方案不适用 以下是我想要完成的 伪 代码 future