自学内容网 自学内容网

longjmp和多线程

看到有人用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   0


typedef 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()回到调度程序。更多的子线程需要自行改进调度程序。自己看代码吧!


原文地址:https://blog.csdn.net/aaasssdddd96/article/details/140567386

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!