防止一段代码在协程中并发执行
Guard a section of code from being executed concurrently in a coroutine
我需要保护一段代码不被并发执行在协程中。防止在多线程环境中并发执行很简单,只需使用 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及其协程TS实现。
C++ 或标准库没有提供基础设施来获取所需的功能。但是,协程 TS 提供了实现可co_await
异步互斥锁的构建基块。
一般的想法是实现一个可等待的,它试图在评估await_suspend
表达式时获取合适的互斥锁。如果无法获取锁,则协程将挂起并添加到等待者队列中,否则执行将立即继续(保持锁(。
互斥锁的unlock
方法从队列中恢复等待者,除非等待者队列为空。
网络上有预先构建的解决方案。我选择了Lewis Baker的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.
}
}
}
相关文章:
- 在另一个线程中调用luaL_error会引发qWarning
- C++在不同线程中改变向量
- C++线程中,没有重载函数接受 X 参数
- 如何从线程中的不同模块调用函数?
- 如何在多线程中正确使用unique_ptr进行多态性?
- 将线程中的数据存储到全局容器的最佳方法?
- 如何在多个线程中创建 QSql数据库连接时防止名称冲突
- 结束另一个线程中使用的对象的生存期
- 通过插槽和信号在不同线程中的两个qt对象之间进行通信
- 在线程中读取无符号整数时,c++ 位是否以原子方式切换?
- C++:在多个线程中访问同一数组/向量的不同单元格是否会产生数据竞赛?
- 如果在 2 个线程中使用,是否值得将size_t声明为 std::atomic?
- zeromq 在 I/O 线程中引发异常
- C++随机uniform_int_distribution在所有线程中返回相同的值
- boost::asio::io_service 在线程中,不会在应用程序退出时退出
- Qt 在另一个线程中无限循环
- 防止一段代码在协程中并发执行
- 并发线程中的 C++ 类对象
- 读取另一个线程中并发运行的 pthread 的本地数据
- 线程安全并发调用外部命令在c++中