生命周期和执行上下文
启动前配置回调、协议选项和 TLS 身份。停止完成前,保持对象及回调捕获的资源存活。 接收回调中的数据 view 只在回调期间有效;需要保留数据时,复制数据。
is_started() 和 is_stopped() 读取原子生命周期状态,对象存活期间可从其他线程查询。
结果只反映查询时的状态,不保证连接随后仍可用,也不代表可以跨线程直接操作 socket。
服务端的 get_listen_address() 和 get_listen_port() 在启动与关闭期间读取同步保护的端点快照。
直接访问 acceptor() 仍需遵守 Asio 的线程约定。
内置 IO 线程池每个通道使用一个 context 和一个工作线程。外部 context 可以由一个
或多个线程调用 run()。每个外部通道使用 strand 串行执行自身回调;下一次回调
可能运行在不同的宿主线程。独立通道可以并行执行,应用仍需同步跨通道共享的状态。
传输端点的客户端和服务端采用以下停止约定:
| 操作 | 约定 |
|---|---|
所有者线程调用 stop() |
发起停止并等待完成 |
request_stop() |
调度停止,可在网络回调中调用 |
所有者线程调用 wait_stopped() |
完成停止,并报告是否允许等待 |
在所涉及 context 或线程池的工作线程调用 wait_stopped() |
返回 false,错误为 operation_not_supported |
对于基于 TCP 的端点,所有者线程等待完成后,已取消的原生 I/O、已受理回调的捕获对象,
以及仍借用服务端资源的 Session 任务均已退出。停止期间拒绝新增用户定时器、延迟 post
和条件等待;显式重新启动后恢复受理。此前已受理的条件回调仍会在关闭期间执行。
应用应先停止外部任务生产者:普通即时 post 仍可提交,因此回调不得无限提交后续工作。
停止后重新启动等生命周期操作须串行执行。TCP 服务端及其 HTTP、WebSocket 和 TLS
派生服务端允许多个所有者线程同时等待停止。若回调捕获对象或 Session 的析构函数
在排空期间从同一所有者线程重入停止,stop() 返回而不等待,并设置
operation_not_supported;wait_stopped() 返回 false,并设置该错误。
数据库客户端另行使用异步 close() 约定,见
数据库关闭与回调所有权。
启动、发送和停止期间,外部 context、运行线程及 work guard 必须持续运行。arknet
不会停止宿主 context。先停止并销毁网络对象,再释放宿主 work guard 并等待运行
线程退出。让 run() 执行完已排队的完成回调后自然返回。io_context::stop()
会停止回调派发,不会完成这个排空过程。所有 context 都应保持存活,直到运行
线程结束;尤其要考虑回调仍持有另一个 context 的 Session 或 strand。
不要在内置 IO 线程池自己的工作线程中销毁线程池;这种情况下析构函数会终止程序。
独立的 arknet::timer 在构造时启动,提供 stop(),没有 request_stop() 或
wait_stopped()。在回调中调用 stop() 不会阻塞;外部 context 持续运行时,
所有者线程可以再次调用 stop(),等待尚未完成的处理函数退出。
进程退出
从 main 返回前,应停止网络任务并释放其所有者。回调在内置 IO 工作线程上释放端点的最后一个引用时,
arknet 会将线程池删除操作交给回收线程。进程清理会等待这些内置线程池、回调及 TLS 资源释放,
然后再进入 OpenSSL 的常规全局清理。回收线程在构造第一个内置 IO 线程池时启动,包含头文件不会启动线程。
使用全局所有者时,每个保存所有权的编译单元都应在声明对象前包含 arknet 的 IO 头文件。
这一约定也覆盖先声明空 shared_ptr、再在 main 中赋值的情况。
若其他编译单元只通过前置声明或类型擦除保存全局所有权,且没有包含该头文件,
则必须在 main 返回前显式清空所有者;arknet 无法推断这类对象的静态析构顺序。
Standalone Asio 的默认配置使用原生线程存储。若应用已先行包含 Asio,或显式选择了旧的 pthread-key
线程存储,应确保各编译单元配置一致,并在退出 main 前销毁所有内置端点和线程池。
外部 IO 的运行线程仍由应用负责停止和等待。