基于switch的协程

3

我知道C和C++中有一种协程的习语或模式:

struct cofunctor {
    int state = 0;

    void operator () () {
        switch ( state ) {
        case 0: // Caller must initialize to 0

            if ( bar1 ) return;

            while ( bar2 ) {
        state = 1; case 1:

                if ( bar3 ) return;

        state = 2; case 2:

                if ( bar4 ) return;
            }
        state = 3; case 3:
            return;
        }
    }
};

随着函数的执行,它会更新一个持久化的checkpoint变量。下次调用时,该值将被用于跳转到执行的中间部分。在实践中,checkpoint不仅仅是一个int类型变量,还可能包含“本地”变量。
我使用C++进行编写。我的应用场景很少出现,因此我希望仅在异常处理期间更新checkpoints。
这种模式是否被实际应用广泛?或者只是作为一种好玩的文档记录存在?在C++中是否存在可重复使用的实现?
(据我所知,Boost.Coroutine使用了不符合规范的堆栈hack,类似于longjmp多线程。我的应用程序很少使用coroutine控制流,并且在众多“线程”中堆栈使用可能非常高,因此不适合使用这种实现方式。)

我认为我最不喜欢的是你必须在函数外部自己维护“状态”。 - Bartek Banachewicz
2
state = 0; 从未被执行。它是为了清晰而添加的吗? - Tobias
barX 变量未定义。它们的含义是什么?你能发一个最小工作示例吗?如果 bar2 && !(bar3 || bar4),那么你会进入无限循环。这是有意为之吗? - Tobias
1
@Tobias state = 0 应该是初始化。已修复。barX 只是代表随机条件。同样,意图是在 if 语句之前发生某些事情。 - Potatoswatter
@Jarod42 谢谢,已经修复了 :) - Potatoswatter
显示剩余3条评论
4个回答

1

我之前在标准C++中实现了可重复使用的堆栈协程,可以让你拥有局部变量(定义为协程类的成员)。要调用协程(我在我的实现中称之为“纤程”),首先需要初始化一个调用栈对象来包含状态,然后启动协程。这里是我定义协程的示例:

struct fiber_func_test
{ PFC_FIBER_FUNC();
  // locals
  unsigned loop_count;
  // test function
  fiber_func_test(unsigned loops_): loop_count(loops_) {}
  bool tick(fiber_callstack &fc_, ufloat &dt_)
  {
    PFC_FIBER_BODY_BEGIN
    while(loop_count--)
    {
      PFC_FIBER_CALL(fc_, dt_, fiber_func_sleep, (0.3f));
    }
    PFC_FIBER_BODY_END
  }
};

loop_count是一个本地变量,其状态存储在堆栈中。以下是它的调用方式:

fiber_callstack fc;
PFC_FIBER_START(fc, fiber_func_test, (10));
while(fc.tick(0.1f))
  thread_nap();

这是代码链接:http://sourceforge.net/p/spinxengine/code/HEAD/tree/sxp_src/core/mp/mp_fiber.h 祝好,Jarkko

1

在C++中是否存在可重用的实现?

这篇文章还谈到了一个位于Boost.ASIO库内部的单头文件、无堆栈实现。

另一个ASIO头文件似乎表明他们已经从以前的状态进一步发展,但我对这个不太了解。它可能与上一个相同,也可能不同。


感谢指点。虽然 ASIO 库不是一个完美的选择,但现在我明白,在设计空间中有许多解决方案,使用类似的技术自己实现也是合适的。 - Potatoswatter

1

0

boost.coroutine不会篡改堆栈 - 它只是使用底层调用约定(由ABI定义)的调用约定。 可以说它只是一个函数调用+存储/恢复指令和堆栈指针。 本地变量会自动保留。


使用C++原语无法存储/恢复指令和堆栈指针。在支持的平台上,它可能在每个ABI的范围内工作,但从可移植的C++角度来看,这仍然被视为一种hack。 - Potatoswatter

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接