Async++ 源码分析3---cancel.h
一、Async++ 代码目录结构
Async++ 项目的目录结构清晰,主要包含根目录下的配置文件、源代码目录、头文件目录以及示例代码目录,具体结构如下:
asyncplusplus/
├── .gitignore # Git 忽略文件配置
├── Async++Config.cmake.in # CMake 配置模板文件
├── CMakeLists.txt # CMake 构建脚本
├── LICENSE # 许可证文件(MIT 许可证)
├── README.md # 项目说明文档
├── examples/ # 示例代码目录
│ └── gtk_scheduler.cpp # GTK 调度器示例
├── src/ # 源代码目录
│ ├── fifo_queue.h # FIFO 队列实现
│ ├── internal.h # 内部头文件(包含类型定义、宏等)
│ ├── scheduler.cpp # 调度器实现
│ ├── singleton.h # 单例模式实现
│ ├── task_wait_event.h # 任务等待事件实现
│ ├── threadpool_scheduler.cpp # 线程池调度器实现
│ └── work_steal_queue.h # 工作窃取队列实现
└── include/ # 头文件目录├── async++.h # 主头文件(对外提供统一接口)└── async++/ # 子模块头文件目录├── aligned_alloc.h├── cancel.h├── continuation_vector.h├── parallel_for.h├── parallel_invoke.h├── parallel_reduce.h├── partitioner.h # 分区器相关定义├── range.h # 范围(迭代器对)相关定义├── ref_count.h├── scheduler.h # 调度器接口定义├── scheduler_fwd.h├── task.h # 任务类定义├── task_base.h # 任务基类定义├── traits.h└── when_all_any.h
二、cancel.h源码分析
2.1 源码
// Copyright (c) 2015 Amanieu d'Antras
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.#ifndef ASYNCXX_H_
# error "Do not include this header directly, include <async++.h> instead."
#endifnamespace async {// Exception thrown by cancel_current_task()
struct LIBASYNC_EXPORT_EXCEPTION task_canceled {};// A flag which can be used to request cancellation
class cancellation_token {std::atomic<bool> state;public:cancellation_token(): state(false) {}// Non-copyable and non-movablecancellation_token(const cancellation_token&) = delete;cancellation_token& operator=(const cancellation_token&) = delete;bool is_canceled() const{bool s = state.load(std::memory_order_relaxed);if (s)std::atomic_thread_fence(std::memory_order_acquire);return s;}void cancel(){state.store(true, std::memory_order_release);}void reset(){state.store(false, std::memory_order_relaxed);}
};// Interruption point, throws task_canceled if the specified token is set.
inline void interruption_point(const cancellation_token& token)
{if (token.is_canceled())LIBASYNC_THROW(task_canceled());
}} // namespace async
这段代码是 Async++ 框架中关于任务取消机制的核心实现,位于 async
命名空间,主要定义了任务取消相关的异常类型、取消令牌及中断点检查功能。以下是详细解析:
2.2. 核心组件说明
(1)task_canceled
异常
- 这是一个空结构体,用于表示 “任务被取消” 的异常类型,通过
LIBASYNC_EXPORT_EXCEPTION
宏导出(确保跨模块可见)。 - 当任务被取消时,框架会抛出该异常,供上层代码捕获并处理取消逻辑。
(2)cancellation_token
类(取消令牌)
一个用于标记 “是否请求取消任务” 的同步原语,核心功能是通过原子变量管理取消状态,供多线程安全访问。
核心成员
std::atomic<bool> state
:原子变量,存储取消状态(false
未取消,true
已取消)。
关键方法
- 构造函数:初始化
state
为false
(默认未取消)。 - 禁用拷贝 / 移动:通过
= delete
显式禁用拷贝构造和赋值,确保令牌唯一且状态不被意外复制。 is_canceled()
:检查是否已取消:- 用
std::memory_order_relaxed
轻量加载state
(性能优先)。 - 若状态为
true
,插入std::memory_order_acquire
内存栅栏,确保后续读取操作能看到取消前的内存状态(多线程同步)。
- 用
cancel()
:设置取消状态:- 用
std::memory_order_release
存储true
,确保之前的写入操作对其他线程可见(同步语义)。
- 用
reset()
:重置取消状态为false
(用std::memory_order_relaxed
,适合单线程重置场景)。
(3)interruption_point
函数(中断点)
- 功能:检查取消令牌状态,若已取消则抛出
task_canceled
异常。 - 作用:作为任务执行过程中的 “检查点”,让任务有机会响应取消请求。
2.3. 设计逻辑与多线程安全性
- 原子操作与内存序:通过
std::atomic
和内存栅栏(acquire
/release
)确保多线程环境下状态的一致性:cancel()
用release
确保 “取消” 操作对其他线程可见。is_canceled()
用acquire
确保读取到取消状态后,能正确同步后续操作。
- 轻量设计:避免复杂锁机制,通过原子变量实现高效的状态查询和修改,适合高频调用场景。
- 显式禁用拷贝:防止令牌被复制后,多个副本独立修改状态导致的逻辑混乱(确保取消操作的唯一性)。
2.4. 用法示例
以下是一个简单场景,展示如何使用这些组件实现任务取消:
#include <async++.h>
#include <iostream>// 模拟一个可被取消的任务
void long_running_task(async::cancellation_token& token) {try {for (int i = 0; i < 10; ++i) {// 每一步检查取消令牌(中断点)async::interruption_point(token);std::cout << "Task running: step " << i << std::endl;std::this_thread::sleep_for(std::chrono::milliseconds(100));}std::cout << "Task completed normally" << std::endl;} catch (const async::task_canceled&) {std::cout << "Task was canceled" << std::endl;}
}int main() {async::cancellation_token token;// 启动异步任务auto task = async::spawn([&token] {long_running_task(token);});// 200ms 后取消任务std::this_thread::sleep_for(std::chrono::milliseconds(200));token.cancel();// 等待任务结束task.get();return 0;
}
输出预期:
Task running: step 0
Task running: step 1
Task was canceled
2.5. 核心作用
- 为 Async++ 框架提供统一的任务取消机制,支持外部触发取消请求(通过
cancellation_token::cancel()
)。 - 允许任务在执行过程中主动检查取消状态(通过
interruption_point
),实现优雅退出。 - 多线程安全的设计确保在并发场景下,取消状态的修改和读取不会出现数据竞争或内存可见性问题。
该机制是并发任务管理的重要组成部分,尤其适用于需要超时控制、用户主动终止等场景。