weixin_42207215 2018-12-07 08:47 采纳率: 0%
浏览 552

利用makecontext做协程


#include <unistd.h>
#include <ucontext.h>
#include <signal.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <sys/time.h>

#define INTERVAL 200000
#define DELAY 50000000
#define BOUND 15
#define STACKSIZE 4096
#define THREADS 16

ucontext_t context[THREADS], myCleanup, myMain;
int status[THREADS];
char myMainArr[STACKSIZE];
struct itimerval clocktimer;
int totalThreads = 0;
int currentThread = 0;
long pos[THREADS];

void cleanup(void);
void task1(int);
void task2(int);
void signalHandler(int signal);

int main( void )
{
    char *myStack[THREADS];
    char myCleanupStack[STACKSIZE];
    int j;
    /* initialize timer to send signal every 200 ms */
    clocktimer.it_value.tv_sec = 0;
    clocktimer.it_value.tv_usec = INTERVAL;
    clocktimer.it_interval.tv_sec = 0;
    clocktimer.it_interval.tv_usec = INTERVAL;
    setitimer(ITIMER_REAL, &clocktimer, 0);
    sigset(SIGALRM, signalHandler);

    getcontext(&myCleanup);
    myCleanup.uc_stack.ss_sp = myCleanupStack;
    myCleanup.uc_stack.ss_size = STACKSIZE;
    myCleanup.uc_link = &myMain;
    makecontext(&myCleanup, (void (*)(void))cleanup, 0);
    // set up your cleanup context here.


    for (j = 0; j < THREADS; j++)
    {

        getcontext(&context[j]); // makecontext must get a context from getcontext
        myStack[j] = (char *)malloc(sizeof(char) * STACKSIZE);
        context[j].uc_stack.ss_sp = &myStack[j];
        context[j].uc_stack.ss_size = STACKSIZE;
        context[j].uc_link = &myCleanup;
        // 1: ready, 2: running 0:finished
        pos[j] = j;

        if (j % 2 == 0){
            printf("Creating task1 thread[%d]\n", j);
            makecontext(&context[j], (void (*)(void))task1, 1, pos[j]);
            // map the corresponding context to task1
        }
        else
        {
            printf("Creating task2 thread[%d]\n", j);
            makecontext(&context[j], (void (*)(void))task2, 1, pos[j]);
            // map the corresponding context to task2
        }
        // you may want to keep the status of each thread using the
        // following array. 1 means ready to execute, 2 means currently
        // executing, 0 means it has finished execution.
        status[j] = 1;
        // You can keep track of the number of task1 and task2 threads
        // using totalThreads.  When totalThreads is equal to 0, all
        // tasks have finished and you can return to the main thread.
        totalThreads++;
    }
    printf("Running threads\n");

    status[currentThread] = 2;
    swapcontext(&myMain, &context[currentThread]);
    // start running your threads here.

    for(j = 0; j < THREADS; j++)
    {
        free(myStack[j]);
    }
    printf("Program terminates successfully\n");
    return 0;
}

void signalHandler(int signal)
{

    //int nextThread;
    int prev, i;
    printf("Get a signal\n");
    //int tmp = currentThread;
    if (status[currentThread] != 0) {
        //printf("status %d is %d\n", currentThread, status[currentThread]);
        status[currentThread] = 1;
    }
    i = (currentThread + 1) % THREADS;
    for (; i != currentThread; i = ((i + 1) % THREADS)) {
        if (status[i] == 1) {
            break;
        }
    }

    prev = currentThread;
    currentThread = i;
    status[currentThread] = 2;
    //printf("prev is: %d  status is: %d   currentThread is: %d status is:%d\n", prev, status[prev], currentThread, status[currentThread]);
    swapcontext(&context[prev], &context[currentThread]);

    return;
}

void cleanup() {

    int prev;
    status[currentThread] = 0;
    totalThreads--;
    if (totalThreads == 0) return;

    int i = currentThread;
    for (i = (currentThread + 1) % THREADS; i != currentThread; i = (i + 1) % THREADS) {
        if (status[i] == 1) {
            break;
        }
    }

    prev = currentThread;
    currentThread = i;
    status[currentThread] = 2;
    swapcontext(&context[prev], &context[currentThread]);

    return;
}

void task1(int tid)
{
    // self explanatory
    int i, count = 1;
    while(count <= BOUND){
        for (i = 0; i < DELAY; i++);
        printf ("task1 [tid = %d]: count = %d\n", tid, count++);
    }
}
void task2( int tid)
{
    // self explanatory
    int i, count = 1;
    while(count <= BOUND){
        for (i = 0; i < DELAY/2; i++);
        printf ("task2 [tid = %d]: count = %d\n", tid, count++);
    }
}

代码如上所述,执行的时候遇到segment fault错误,第一次使用makecontext,不知道哪的问题,调试不出来,望大神支招。

代码实现的意思是:
模拟16个线程执行task1和task2,中间会有alarm信号中断,中断的时候会使用makecontext保存当前上下文,执行下一个上下文。

其中status保存当前线程的状态,0为结束,1为可以执行,2为执行中

最后,执行完成的线程会调用cleanup函数设置status为0,然后,alarm信号中断的时候不会选取该线程执行。

请指教。

  • 写回答

0条回答 默认 最新

    报告相同问题?

    悬赏问题

    • ¥15 虚拟机打包apk出现错误
    • ¥30 最小化遗憾贪心算法上界
    • ¥15 用visual studi code完成html页面
    • ¥15 聚类分析或者python进行数据分析
    • ¥15 逻辑谓词和消解原理的运用
    • ¥15 三菱伺服电机按启动按钮有使能但不动作
    • ¥15 js,页面2返回页面1时定位进入的设备
    • ¥50 导入文件到网吧的电脑并且在重启之后不会被恢复
    • ¥15 (希望可以解决问题)ma和mb文件无法正常打开,打开后是空白,但是有正常内存占用,但可以在打开Maya应用程序后打开场景ma和mb格式。
    • ¥20 ML307A在使用AT命令连接EMQX平台的MQTT时被拒绝