misc-coroutine-hostile-raii¶
检测在协程中跨越挂起点的某些敌对 RAII 类型对象的持久化。 这些敌对类型包括可作用域锁定类型和属于可配置拒绝列表的类型。
某些对象要求它们在创建它们的同一线程上被销毁。 传统上,此要求通常被表述为“必须是局部变量”,在假设局部变量始终以这种方式工作的情况下。 但是对于 C++20 协程来说,这是不正确的,因为中间的 co_await
可能会导致协程挂起,然后在另一个线程上恢复。
需要在同一线程上销毁的对象的生命周期不应包含 co_await
或 co_yield
点。 如果你创建/销毁一个对象,你必须在不允许多线程挂起的情况下进行。
以下类型被视为敌对类型
可作用域锁定类型: 跨越挂起点的持久化的可作用域锁定对象是有问题的,因为此对象持有的锁可能被另一个线程解锁。 这将是未定义的行为。 这包括所有用
scoped_lockable
属性注释的类型。属于可配置拒绝列表的类型。
// Call some async API while holding a lock.
task coro() {
const std::lock_guard l(&mu_);
// Oops! The async Bar function may finish on a different
// thread from the one that created the lock_guard (and called
// Mutex::Lock). After suspension, Mutex::Unlock will be called on the wrong thread.
co_await Bar();
}
选项¶
- RAIITypesList¶
一个以分号分隔的限定类型的列表,这些类型不应允许跨越挂起点持久化。 例如:
my::lockable; a::b;::my::other::lockable;
此选项的默认值为 “std::lock_guard;std::scoped_lock”。
- AllowedAwaitablesList¶
一个以分号分隔的限定类型的列表,这些类型表示可安全等待的类型,即使在作用域中存在敌对的 RAII 对象。
当
awaitable
类型的表达式属于此列表时,co_await
-ing 该表达式被认为是安全的。 跨越此类co_await
表达式的 RAII 对象被认为是安全的,因此不会被标记。示例用法
// Consider option AllowedAwaitablesList = "safe_awaitable" struct safe_awaitable { bool await_ready() noexcept { return false; } void await_suspend(std::coroutine_handle<>) noexcept {} void await_resume() noexcept {} }; auto wait() { return safe_awaitable{}; } task coro() { // This persists across both the co_await's but is not flagged // because the awaitable is considered safe to await on. const std::lock_guard l(&mu_); co_await safe_awaitable{}; co_await wait(); }
例如:
my::safe::awaitable;other::awaitable
此选项的默认值为空字符串 “”。