- 论坛徽章:
- 2
|
continuation的概念
粗略地说, continuation就是“接下来要做什么”。。。
- void f(int x, int y, int root)
- {
- printf("%s x+y = %d\n", root? "#": "$", x+y);
- printf("%s x-y = %d\n", root? "#": "$", x-y);
- }
复制代码 “printf("%s x+y = %d\n", root? "#": "$", x+y)” 的continuation就是:
1. 继续执行下面一条printf
2. f返回它的调用者
3. 在返回处继续执行知道这个线程中止(continuation是有界限的)
“x+y”的continuation说明起来就更复杂一些。 假设 v 是 “x+y”的结果, “x+y”的continuation可能是:
1. “printf("%s x+y = %d\n", root? "#": "$", v)” 接着是这整个表达式的continuation, 就是上面说的直到这个线程中止的剩余部分。
2. “printf("%s x+y = %d\n", "$" , v)” 以及后续continuation
3. “printf("%s x+y = %d\n", "#" , v)” 以及后续continuation
...
C语言规定了两个printf的顺序, 必须先执行第1个, 再执行第2个。 所以前一个printf的continuation说明起来更容易一些。
C语言并没有规定printf的参数的求值顺序, 所以就此处就不像前面那样容易说明。。。
如果 root? "#": "$" 比 “x+y”后求值, 那就是1的情况。
如果 root? "#": "$" 比 “x+y”先求值, 那2就是root非0的情况, 3就是root为0的情况。
实际上还可以继续细分, 比如 “root” “"%s x+y = %d\n"”这些子表达式。
总之, continuation 是等待这一个值的。
“printf("%s x+y = %d\n", root? "#": "$", x+y)” 也等待这printf的返回值, 只是立即丢弃了, 不容易看出来。
而“x+y”的continuation就需要“x+y”的求值结果。
因此, 哪怕是C语言,也存在continuation。 但这些continuation不能拿给程序员继进行操作, 所以没啥卵用。。。
C语言也有可以让程序员使用的continuation, 就是jmp_buf。
- jmp_buf k;
- int x = setjmp(k);
- ...
复制代码 “setjmp(k)”的continuation就是“int x = v; ...”, 即对x赋值, 以及后续表达式, 直到线程中止。 其中v是setjmp(k)的值。
这个continuation就是程序员可以操作的了。 可以通过“longjmp(k, val)” 调用该continuation, 即是回到“setjmp(k)”处, 为x提供一个值, 并继续执行。
不过C语言规定longjmp只能从调用链的“深处”往“浅处”跳, 不能反过来。 于是限制了它的用处。。。
并且用的时候还要各种小心。。。 C++的析构函数。。。 volatile。。。 sign mask。。。。 于是肯定就会出现“setjmp/longjmp Considered Harmful”这样的论点。。。
除了C语言标准外, windows下有fiber, posix里有ucontext。 它们都让程序员可以操作continuation。
continuation最出名的应该是Scheme里的call-with-current-continuation(一般简称为call/cc, 但前者才是r5rs里有的, call/cc不是)。
call/cc 是一种 undelimited continuation , 其实不如 delimited continuation 好用。。。
delimited continuation好像正是源自ML系列的语言。。。 你可以去搜一下, reset/shift或者prompt/control之类的, 它们都是delimited continuation。
还有一种与continuation有关的概念叫continuation passing style。 俗称callback或callback hell。。。 |
|