看到有人用setjmp()/longjmp() 做的多线程例子。这种方法极容易造成堆栈冲突。非常不赞成这么用。如果用多线程,linux当然用pthread线程库。windows当然用CreateThread()。
原例子这里就不展示了。感兴趣可以自己搜索“setjmp 协程”。这里做了大幅修改,把原来的“主控(即主线程)和子线程”改为“主控(即调度程序)和两个子线程”。3个线程合作运行。但仍然有堆栈冲突的危险。最好每个线程有独立的运行栈,那样就又回到OS自己的多线程上来了。
这里分享上来,只为了爱好者扩大知识面,并不代表就可以实用了。调试,评估,然后扔掉:
#include <stdio.h>
#include <string.h>
#include <setjmp.h>
#include <stdlib.h>typedef int BOOL;
#define TRUE 1
#define FALSE 0typedef struct _Context_ {jmp_buf mainBuf;jmp_buf coBuf;int finish;struct {jmp_buf buf;int state;} thread[2];
} Context;Context gCtx;
static int next_thread;#define resume(i) \if (gCtx.thread[i].state==0) \{ \longjmp(gCtx.thread[i].buf, 1); \}#define yield() \if (0 == setjmp(gCtx.coBuf)) \{ \memcpy(gCtx.thread[thread_id].buf, gCtx.coBuf, sizeof(jmp_buf));\longjmp(gCtx.mainBuf, 1); \}void coroutine_function(void *arg)
{int n = 0;int thread_id = *(int *) arg;while (TRUE) {int i;if (++n > 10) break;printf("\n*** coroutine: thread_id=(%d) working \n", thread_id);for (i = 0; i < 10; ++i) {printf(".");}printf("\n*** coroutine: suspend \n");yield();}printf("\n*** coroutine: finish(%d)\n", n);gCtx.finish = 1;gCtx.thread[thread_id].state = 1;yield();
}typedef void (*pf) (void *);
BOOL start_coroutine(pf func, void *arg)
{int reserve[256];int thread_id;extern int run;thread_id = next_thread++;run = thread_id;func(&thread_id);return TRUE;
}void coroutine_main(void *arg)
{int i;int n = 0;int thread_id;thread_id = *(int *) arg;if (setjmp(gCtx.thread[thread_id].buf)!=0) goto next;start_coroutine(coroutine_function, NULL);next:while (TRUE) {if (gCtx.finish) break;printf("\n=== main() count(%d): thread_id=(%d) working \n", ++n, thread_id);for (i = 0; i < 10; ++i) {printf("%d%d%d%d%s", i, i, i, i, "-");}printf("\n=== main: suspend \n");yield();}printf("thread_id main=%d\n", thread_id);gCtx.thread[thread_id].state = 1;yield();
}int run;
int sched()
{int s;if (run == 0) s = 1; else s = 0;if (gCtx.thread[s].state == 0) run = s;return run;
}int main()
{int i;if (setjmp(gCtx.mainBuf)!=0) goto resched;start_coroutine(coroutine_main, NULL);while (TRUE) {resched:i = sched();printf("sched thread(%d) to run\n", i);if (gCtx.thread[i].state == 0) {resume(i);} else break;}printf("done\n");return 0;
}
子线程用start_coroutine()启动。下一个子线程必须用上一个子线程启动。子线程结束后不能return返回,而是把状态置为1,表示结束,然后用yield()回到调度程序。更多的子线程需要自行改进调度程序。自己看代码吧!