模块契约Future 与 Promise

结果与所有权

  • xrtPromiseResolve 只借用值。调用方必须保证值至少活到全部 Future 引用释放之后。
  • xrtPromiseResolveOwned 仅在成功完成时接管值;重复完成失败时,值仍归调用方。
  • xrtPromiseReject 增加不可变错误引用,调用方仍释放自己的错误引用。
  • 只有第一个终态写入成功。重复写入返回 false 并设置 XERR_STATE。
  • Future 最后释放时执行 owned 值析构;析构过程在 Future 内部锁外运行。

xrtFutureDone 和 xrtPromiseDone 判断对应端点是否已经进入终态。xrtFutureResult 返回借用的 xfutureresult,xrtFutureError 直接返回失败终态中的借用错误。结果中的值和错误只在调用方继续持有 Future 引用时有效。Pending 返回 false 并设置 XERR_AGAIN。xrtFutureValue 是常见成功路径助手;对失败、取消或关闭状态调用时,会把对应结构化错误设置到当前执行上下文。

xrtPromiseForward 把一个已经进入终态的源 Future 安全透传到目标 Promise。失败错误会增加引用;成功值保持借用语义,同时由目标 Future 保留源引用。透传所有者链使用迭代释放,因此深延续链的销毁不会递归耗尽 C 调用栈。源仍为 Pending、目标已经完成或发生自透传时返回 false。

裁剪与依赖

层裁剪宏依赖能力
Future 核心XRT_FEATURE_FUTUREcancel结果、所有权、同步等待、协作取消
Future 适配桥XRT_FEATURE_FUTURE_BRIDGEfuture、thread、atomic异步操作、Promise 与取消监听的一次性装配
Future 延续XRT_FEATURE_FUTURE_CONTINUEfutureContinue、Then、Catch、Finally 与安全结果透传
Future 组合器XRT_FEATURE_FUTURE_COMBINEfutureAny、All、Race 与源结果保活
协程等待桥XRT_FEATURE_FUTURE_COROUTINEfuture、coroutine_scheduler不阻塞调度线程的 await

延续链、线程池执行器和结构化任务组属于后续独立层,不会增加只需要 Future 核心的程序体积。

统一等待边界

当前契约不再提供 xwaitsrc 或网络专用 xnetwaitsrc。异步操作直接返回同一种 xfuture:Future 同时携带终态、成功值、结构化错误、取消入口和所有权,因此线程 等待、协程 Await、延续、组合器和 TaskGroup 不需要先把它包装成另一个等待对象。

TCP 可读、可写、Drain、Accept 等只表示条件就绪的场景仍通过对应的 xrtNet*WaitAsync 返回 Future;真正接收数据或建立连接的操作返回拥有结果的 Future。 这种分层保留“只观察条件”和“取得结果”两类能力,但不复制 bool、xnet_result 和 Future 终态三套互相转换的状态模型。

需要组合不同对象类型时,上层只保存 xfuture*,通过 Any、All、Race 或 TaskGroup 协调;完成后按创建该 Future 的操作契约解释值。底层事件端口的 readiness/completion 观察仍属于网络引擎内部原语,不作为跨模块类型擦除接口泄漏到业务层。

状态

xfuturestate 只有五个稳定状态:

  • XFUTURE_PENDING:生产端尚未写入结果。
  • XFUTURE_RESOLVED:成功,可读取 Value。
  • XFUTURE_FAILED:失败,可读取不可变 xerror。
  • XFUTURE_CANCELLED:生产过程确认以取消结束。
  • XFUTURE_CLOSED:最后一个生产端在未完成时离开,或显式关闭。

等待一个失败、取消或关闭的 Future 仍返回 XWAIT_OK,因为等待动作已经完成。调用方随后通过 xrtFutureState 或 xrtFutureResult 判断操作结果。XWAIT_TIMEOUT 和 XWAIT_CANCELLED 只描述等待者自身提前停止等待。

创建与生命周期

创建成功后,调用方各拥有一个 Promise 和 Future 引用。pParentCancel 可以为空;非空时,新 Future 的取消令牌继承父链。xrtPromiseRef、xrtFutureRef 分别增加端点引用,xrtPromiseDestroy、xrtFutureDestroy 分别释放。

最后一个 Promise 引用在 Pending 状态释放时,Future 自动进入 XFUTURE_CLOSED 并请求取消,避免消费者永久等待。已经完成的 Future 不会因 Promise 释放而改变状态或取消令牌。

Future 的内部完成监听按注册顺序执行。嵌套完成会追加到当前 Fiber 或线程的无分配派发队列,由最外层完成调用迭代排空;因此组合器和后续延续链的级联深度不会转化为 C 调用栈深度。

无分配终态监听

xfuturewatch 是调用方提供存储的底层终态监听节点,使用 XRT_FUTURE_WATCH_STORAGE_SIZE 固定不透明空间,不为每次监听分配内存。 xfuturewatchproc 接收通知上下文;可选的 xfuturewatchreleaseproc 在节点被 Future 接管后,于完成通知或成功摘除时执行一次。

xrtFutureWatchAdd 返回 XFUTURE_WATCH_PENDING 时,Future 已接管节点;返回 XFUTURE_WATCH_READY 时源已经完成,节点仍归调用方且不会执行 Release; XFUTURE_WATCH_ERROR 表示参数或状态无效。xrtFutureWatchDetach 只尝试摘除尚未 开始通知的节点,成功时同步执行 Release;xrtFutureWatchRemove 还会等待已经开始的 通知结束,不能从该 Watch 自己的通知中调用。xfuturewatchresult 只描述注册结果, 不替代 Future 的终态。

取消

xrtFutureCancel 只发出协作取消请求,Future 保持 Pending,直到生产端完成、确认取消或关闭。这样资源回收、内核 I/O 取消和任务退出不会被一个伪造终态掩盖。令牌访问函数返回新增引用,使用完毕后调用 xrtCancelDestroy。

生产过程可以处理取消后正常返回值;取消请求与最终状态是两个正交事实。只有 xrtPromiseCancel 才写入 XFUTURE_CANCELLED。

xrtPromiseCancel、xrtPromiseClose 和最后一个 Promise 引用的隐式关闭使用两阶段发布:先独占终态写入权并完成取消令牌通知,再发布 CANCELLED/CLOSED、唤醒等待者和执行 Future 回调。因此任何已经观察到取消或关闭终态的线程都必然也能观察到令牌已经请求;令牌监听执行期间 Future 仍显示为 Pending,但其他生产者已经不能抢占终态。取消监听不得等待同一个 Future 进入终态,否则会形成生产端自等待。

同步等待

时间单位统一为毫秒,截止时间使用单调时钟。等待支持任意数量线程,并对虚假唤醒、完成与超时竞争、取消监听注销竞争进行循环检查。Future 终态与外部取消回调在同一把 Future 锁下线性化:终态先取得锁时返回 XWAIT_OK;取消先取得锁时,本次等待固定返回 XWAIT_CANCELLED,即使 Future 在等待线程恢复前已经完成也不会覆盖该结果。截止时间在相同循环边界检查,Future 尚未终结时到期返回 XWAIT_TIMEOUT。调用方取消只停止当前等待,不取消 Future;需要同时取消生产过程时另行调用 xrtFutureCancel。

协程等待

这些函数只能在 xcosched 管理的协程中调用。等待节点由当前协程栈保存,不产生每次 await 堆分配;Future 可由任意线程完成,完成通知通过内部代际令牌投递回所属调度器。通知早于真正 park 时不会丢失,等待退出后也不会污染下一次 park;独立的公共 xrtCoWake 不会被 Await 清理过程误消费。提前唤醒、超时和协程取消都会安全摘除等待节点。

协程取消使 Await 返回 XWAIT_CANCELLED,但不改变被等待 Future 的状态,也不自动决定当前协程的终态。用户过程可以完成清理后正常返回;只有显式调用 xrtCoConfirmCancel,当前协程才以 XCORO_TERM_CANCELLED 终结。对于一次调用者独占的网络 Future,放弃操作时应先调用 xrtFutureCancel,让 TCP/UDP 等待节点及时摘除;共享 Future 则由拥有生产过程取消权的一层决定。

组合器

组合器只协调多个 Future 的生命周期,不复制、不接管源值,也不把某个源的失败冒充为组合器自身失败:

  • Any 在第一个源进入任意终态时,以 xfuturepick 成功完成,不改变其余源。
  • Race 与 Any 的选择结果相同,随后向其余源发出协作取消请求;源生产端仍决定各自最终状态。
  • All 等全部输入槽位进入终态后,以保序的 xfutureall 成功完成。重复源按重复槽位计数;空集合立即成功完成。
  • 输入数量同时受连续分配大小和内部引用计数上限约束,超出任一边界都会在读取输入数组前以 XERR_RANGE 失败。
  • xfuturepick 和 xfutureall 都是借用视图,只在持有组合 Future 引用时有效。组合器内部保留全部源引用,因此通过视图读取源结果不会悬空。
  • 取消尚未完成的组合 Future 会确认组合器自身为 XFUTURE_CANCELLED、摘除全部源监听,并向源发出取消请求;源 Future 不会被伪造为已取消。

这种契约把“多个操作何时达到协调点”和“每个操作以什么结果结束”分开。调用方可以直接检查 pPick->Future 或 pAll->Futures[i] 的状态、值和结构化错误,也可以在上层任务组中实现失败即取消、收集全部错误等策略。

Future 桥

桥解决"异步操作先返回 Future、结果稍后才到"的装配竞态:Ready 之前的终态写入被挂起,Ready/Fail 决定放行或回收。

TLS 监听器

监听器把 TCP 绑定与异步接入组合为单入口;Accept 三形态覆盖 pull(非阻塞/Future/阻塞)消费模型。

TLS 拨号

拨号把 DNS 解析、TCP 竞争连接与 TLS 握手组合为一次异步操作,提供回调式与 Future 式两个入口。

TLS Stream

TLS Stream 组合 TCP 传输与 TLS 会话为单一明文接口:Worker 专用同步收发(Send/Buffer/Pullup/Read/Consume)与任意线程 Future 收发(SendAsync/RecvAsync/WaitAsync)双模型。

Watch 与聚合器的物理拥有图

xrtFutureWatchInitTraced(watch, notify, release, data, trace) 在初始化时固定 release(data) 所释放的强拥有槽;release 和 trace 必须非空。唯一拥有的上下文 折叠到源 Future 的边,共享引用计数上下文必须作为独立物理节点报告。初始化不 分配、不消费、不执行回调;只有 WatchAdd 返回 PENDING 才转移注册释放权。 READY / ERROR 时仍由调用方释放数据。公开 Watch 继续为 64 字节,不改变旧 Init。

Future Inspect 遍历已描述的挂接 Watch;任一未知 waiter 仍拒绝整个检查,不能 假装其数据是叶子。注册、通知、释放、图检查与之后提交之间仍需要调用方保证 整个图静止和所有回调代码驻留;本接口不建立安全点,不自动使语言 frame 可检查。

Any / All / Race 的共享上下文现在按实际 RC 身份入图:每个 Source 槽各一条边, 重复输入保留重复边;Pick 和 All 仅借用这些槽,不产生第二组虚假拥有边。挂起时 每个注册 waiter 持有一个 group 引用;输出另以真实 producer 引用拥有 group, group 又拥有 Promise。拥有型取消监听保有一个实际 group 引用,令牌链表仍只 借用监听。终态原生结果通过策略化原子发布保有 group;终态时取消监听实际注销, 不再留到原生结果销毁。未认证映射上下文仍不被自动准入为可收集节点。 未知源载荷/源 waiter 继续导致拒绝;图检查本身不执行通知、取消、析构或收集。

验证入口 tools/check_future_waiter_ownership.ps1 分别覆盖 Watch 的 PENDING / READY / detach 所有权、重复输入、取消/空集合、原生别名及分配失败原子性。

示例

网络适配层直接返回同一种 xfuture。TCP、UDP、TLS Stream、HTTP 和 WebSocket 的 Future 都可以交给上述同步等待、组合器、延续和协程 Await;协议层只定义 成功值、取消点和终态映射,不复制 Future 或协程状态机。

标准库和扩展库的异步适配器共用公开的 xfuturebridge;对象使用 XRT_FUTURE_BRIDGE_STORAGE_SIZE 字节不透明存储,可直接嵌入操作上下文。底层操作可以 在监听安装期间并发完成,但只有装配进入 READY 后才能发布 Future;监听分配 失败会进入 FAILED,底层晚到结果只执行对应资源回收,不会留下回调。这个底层 契约由 tests/concurrency/test_future_bridge_oom.c 独立验证,DNS、TCP、TLS 与 HTTP 适配器不再分别复制这一段易错生命周期代码。

xrtFutureBridgeCreate 创建 Future/Promise 对;xrtFutureBridgeInit 则借用一个 已有 Promise,两种路径都不接管 Promise 所有权。适配器最终仍须调用 xrtPromiseDestroy(xrtFutureBridgePromise(&bridge))。xrtFutureBridgeReady 与 xrtFutureBridgeFail 只能发布一次,重复发布以状态错误失败。完成回调先调用 xrtFutureBridgeWait 跨过极短装配窗口,再调用 xrtFutureBridgeUnwatch 与正在 执行的取消回调汇合。Wait 返回 false 时只回收底层结果,不写入 Promise。

适配器发布终态前必须先固定成功值或错误引用、注销取消监听、销毁底层操作, 并归还等待节点、缓存预算、网络对象引用和临时 Engine 租约。因而观察到网络 Future 终态时,适配器上下文不会再被迟到回调访问,也没有只为该操作保留的 Engine 活动对象。成功 Future 明确拥有的 Stream、Packet、响应或连接是公开结果, 其生命周期继续由 Future 引用保护,不属于内部临时资源。协作取消同样遵守该屏障, 不会先伪造 CANCELLED 再在后台回收操作。

完整示例位于 examples/concurrency/future/main.c、 examples/concurrency/future_combine/main.c、 examples/concurrency/future_coroutine/main.c 与 examples/tls/stream_future/main.c、examples/tls/dial_future/main.c。 其中 future_combine 同时演示 Any、All、Race、胜出源索引和 Race 的协作取消语义。

显式结果生命周期与物理控制块接管

xrtPromiseResolveOwnedPolicyV1 在发布时绑定不可变的 xfuturepayloadownershipv1 { size, Drop, Trace }。该策略与代码必须比所有结果 活得更久,context 固定为空;失败不消费结果。它与旧的 xrtPromiseResolveOwnedTraced 不同:提供追踪函数并不自动获得生命周期认证。

回收器在同一次全图 freeze 中、调用 Count/Trace 之前,用 xrtFutureOwnershipAdapterV1 及明确的策略身份白名单接纳物理控制块。 Future 与 Promise 是同一个节点,生产端引用不能凭估计扣除。未认证的拥有 载荷、正在完成的控制块、所有已注册 waiter,以及有取消观察者的令牌均拒绝。 转发 Owner、错误 Cause、取消 Parent 和载荷内的拥有边仍需逐一独立接纳。

Claim 可在提交前恢复;Clear 仅在最终重验的同一个 freeze 中隔离结果。 无观察者的 pending 控制块此时进入 CLOSED 并请求其自身取消,不通知用户代码。 真实结果、Owner、Error、Cancel 引用延迟到 freeze 外的 Finish 释放;重复 Finish 不重复消费。已 Clear 的控制块拒绝新增 Future/Promise 引用和结果读取。 普通终末释放仅对显式策略退出自身 mutation 后执行 Drop;旧回调保持保守隔离。 这不是对 pending task、Watch、原生回调或任意模块卸载的普遍授权。

xfuturebridge类型

Future 桥的内部状态保持不透明,可直接嵌入异步操作上下文。

字段类型语义
Alignmentuint64对齐(二次幂)
typedef union xfuturebridge { uint64 Alignment; uint8 Storage[XRT_FUTURE_BRIDGE_STORAGE_SIZE]; } xfuturebridge;
Future 桥

xrtFutureBridgeInit函数

使用一个已有 Promise 初始化桥;Promise 的所有权仍由调用方持有。桥解决"异步操作先返回 Future、结果稍后才到"的装配竞态。

bool xrtFutureBridgeInit(xfuturebridge* pBridge, xpromise* pPromise)

参数

参数方向约束说明
pBridge输出非空、32 字节固定存储可嵌入异步操作上下文
pPromise输入非空、借用调用方持有的 Promise
返回值
返回含义失败时状态
true桥已就绪—
false参数非法XERR_ARGUMENT
错误
  • XERR_ARGUMENT — 指针为空或参数非法

范例已编译验证

concurrency/bridge_tour · Init · 观察

		!xrtFutureBridgeInit(&Bridge2, pPromise2) ||

xrtFutureBridgeCreate函数

创建 Future/Promise 对并初始化桥;返回的 Future 由调用方持有。

xfuture* xrtFutureBridgeCreate(xfuturebridge* pBridge, xcancel* pParent)

参数

参数方向约束说明
pBridge输出非空桥存储
pParent输入允许空父取消令牌
返回值
返回含义失败时状态
非空消费端 Future—
NULL创建失败XERR_ARGUMENT / XERR_MEMORY
错误
  • XERR_ARGUMENT — 指针为空或参数非法
  • XERR_MEMORY

范例已编译验证

concurrency/bridge_tour · Create · 观察

	pFuture = xrtFutureBridgeCreate(&Bridge, NULL);

xrtFutureBridgePromise函数

返回桥借用的 Promise;调用方负责按原有所有权契约销毁它。

xpromise* xrtFutureBridgePromise(const xfuturebridge* pBridge)

参数

参数方向约束说明
pBridge输入非空桥
返回值
返回含义失败时状态
非空借用的 Promise(不增引用)—
NULL参数非法XERR_ARGUMENT
错误
  • XERR_ARGUMENT — 指针为空或参数非法

范例已编译验证

concurrency/bridge_tour · Create · 观察

		((pBorrowed = xrtFutureBridgePromise(&Bridge)) == NULL) ) {

xrtFutureBridgeWatch函数

把 Future 的协作取消转发给底层异步操作。

bool xrtFutureBridgeWatch(xfuturebridge* pBridge, xcancelproc pCancelProc, ptr pCancelData)

参数

参数方向约束说明
pBridge输入/输出非空桥
pCancelProc输入非空取消回调
pCancelData输入任意值原样传给回调
返回值
返回含义失败时状态
true监听已建立—
false参数或状态非法XERR_ARGUMENT / XERR_STATE
错误
  • XERR_ARGUMENT — 指针为空或参数非法
  • XERR_STATE — 未初始化或已注销

范例已编译验证

concurrency/bridge_tour · Watch · 观察

	if ( !xrtFutureBridgeWatch(&Bridge, exampleCancel,
			(ptr)&bCancelled) ||

xrtFutureBridgeReady函数

发布装配成功,允许底层完成回调向 Promise 写入终态。

bool xrtFutureBridgeReady(xfuturebridge* pBridge)

参数

参数方向约束说明
pBridge输入/输出非空桥
返回值
返回含义失败时状态
trueReady 之前的挂起终态写入被放行—
false状态非法(已发布)XERR_STATE
错误
  • XERR_STATE — 已发布过 Ready/Fail

范例已编译验证

concurrency/bridge_tour · Watch · 观察

		!xrtFutureBridgeReady(&Bridge) ||

xrtFutureBridgeFail函数

发布装配失败,要求底层完成回调只回收结果。

bool xrtFutureBridgeFail(xfuturebridge* pBridge)

参数

参数方向约束说明
pBridge输入/输出非空桥
返回值
返回含义失败时状态
true后续终态写入将被拒收—
false状态非法(已发布)XERR_STATE
错误
  • XERR_STATE — 已发布过 Ready/Fail
  • 注:Promise 归调用方所有,直接向 Promise 写终态仍合法

范例已编译验证

concurrency/bridge_tour · Fail · 观察

		!xrtFutureBridgeFail(&Bridge2) ||
		xrtFutureBridgeWait(&Bridge2) ) {

xrtFutureBridgeWait函数

等待极短的装配窗口,并返回底层结果能否写入 Promise。

bool xrtFutureBridgeWait(const xfuturebridge* pBridge)

参数

参数方向约束说明
pBridge输入非空桥
返回值
返回含义失败时状态
true已 Ready:结果可写入 Promise—
false已 Fail:只回收结果(不设错,是查询结果)—
错误
  • 无 — 返回值即答案

范例已编译验证

concurrency/bridge_tour · Watch · 观察

		!xrtFutureBridgeWait(&Bridge) ||

xrtFutureBridgeUnwatch函数

注销取消监听,并与正在执行的取消回调汇合。

void xrtFutureBridgeUnwatch(xfuturebridge* pBridge)

参数

参数方向约束说明
pBridge输入允许空空 = 空操作
返回值
返回含义失败时状态
无返回后取消回调不再触发—
错误
  • 无 — 注销不失败

范例已编译验证

concurrency/bridge_tour · 收尾 · 观察

	xrtFutureBridgeUnwatch(&Bridge);
补充参考 · 契约见公共头注释

xrtFutureBridgeWatchOwnedV1函数

契约注释见公共头文件。

XRT_API bool xrtFutureBridgeWatchOwnedV1(xfuturebridge* pBridge, ptr pData, const xcancelwatchownershipv1* pPolicy)

xrtFutureBridgeWatchOwnershipV1函数

契约注释见公共头文件。

XRT_API bool xrtFutureBridgeWatchOwnershipV1(const xfuturebridge* pBridge, xrtownershipref* pReference)

常量索引常量

以下常量在本页所属头文件中定义,语义见公共头注释。

常量说明
XRT_FUTURE_BRIDGE_STORAGE_SIZE见头文件注释