为何C++测试库libunifex会执行两次计算?相关技术疑问
关于libunifex中Sender复用导致重复执行的问题解答
问题背景
测试libunifex库时发现执行行为不符合预期,示例代码如下:
#include <unifex/sync_wait.hpp> #include <unifex/then.hpp> #include <unifex/when_all.hpp> #include <unifex/single_thread_context.hpp> #include <iostream> int main() { using namespace unifex; single_thread_context context; sender auto s0 = schedule(context.get_scheduler()); sender auto s1 = then(s0, [](){ std::cout << "do complex computation" << std::endl; }); sender auto s21 = then(s1, [](){}); sender auto s22 = then(s1, [](){}); sync_wait(when_all(s21, s22)); }
需求是让s1中的复杂计算仅执行一次,但实际被执行了两次,存在两个疑问:
- 该需求(让
s1仅计算一次)是否被P2300r1文档支持? - libunifex中未实现的
split函数是否与该需求有关?
解答
1. P2300r1对该需求的支持情况
P2300r1定义的Sender核心语义是:每次启动(start)Sender都会完整执行其对应的工作流。你当前的代码中,when_all会分别启动s21和s22,而这两个Sender各自依赖s1,因此会分别启动s1两次,导致计算逻辑重复执行,这是符合标准语义的。
但P2300r1明确支持"共享Sender执行结果"的场景——即让一个Sender的执行结果被多个下游Sender复用,避免重复执行上游逻辑。你的需求完全符合标准文档的设计目标,只是需要使用专门的多播/共享机制来实现,而非直接复用同一个Sender实例。
2. split函数与需求的关系
是的,split函数正是解决这类问题的核心工具。它的作用是将一个普通Sender转换为可被多个下游订阅的Sender,确保上游工作流仅执行一次,执行结果被所有下游Sender复用。由于libunifex目前尚未实现split,所以你无法直接通过该函数满足需求。
临时替代实现方案
在split函数实现前,可以通过shared_future结合libunifex的Sender机制模拟类似效果,示例如下:
#include <unifex/sync_wait.hpp> #include <unifex/then.hpp> #include <unifex/when_all.hpp> #include <unifex/single_thread_context.hpp> #include <future> #include <iostream> int main() { using namespace unifex; single_thread_context context; // 先执行一次s1的逻辑,用shared_future缓存结果 auto shared_result = sync_wait(then(schedule(context.get_scheduler()), [](){ std::cout << "do complex computation" << std::endl; return 0; })).value(); auto shared_fut = std::make_shared<decltype(shared_result)>(shared_result); // 下游Sender复用缓存的结果,无需重复执行上游逻辑 sender auto s21 = then(schedule(context.get_scheduler()), [shared_fut](){ // 此处可使用shared_fut中的结果 }); sender auto s22 = then(schedule(context.get_scheduler()), [shared_fut](){ // 此处可使用shared_fut中的结果 }); sync_wait(when_all(s21, s22)); }
内容的提问来源于stack exchange,提问作者macomphy
相关产品推荐
相关产品推荐

