在这个类似线程的实现中,当时间用完时如何切换上下文?

问题描述 投票:0回答:0

我已经设置了 5 秒的时间并在

test1()
函数中调用睡眠(15)它应该从
test1()
切换到开始运行
test2()
但是在时间
find_next_to_run()
switch_thread()
被称为从超时单线程/线程切换处理程序
thread_time_run_out()
我通过调用
uthread_create(test2, &a2); in the main function, isn't in there so the 
test2()
doesn't get executed at time out of
test1()` 添加的 #2 线程。我想念什么?我该如何解决?

这是我的完整代码:

uthread.h


#ifndef UTHREAD_H
#define UTHREAD_H

#include <ucontext.h>

#define STACK_SIZE 32768
#define NUM_MAX_THREADS 32
#define TIME_SLICE 100

typedef void (*start_routine_t)(void*);

typedef enum THREAD_STATE
{
    THREAD_STATE_NONE,
    THREAD_STATE_PENDING,
    THREAD_STATE_RUNNING,
    THREAD_STATE_DONE,
} THREAD_STATE_T;

typedef struct thread
{
    ucontext_t context;
    void* stack;
    THREAD_STATE_T state;
    start_routine_t start_routine;
    void* routine_arg;
    int done;
    int id;
} thread_t;

void* create_stack(void);
void no_memory(void);
thread_t* create_thread_info(start_routine_t, void*);
thread_t* uthread_create(start_routine_t, void *restrict arg);
void uthread_release(thread_t **th);
thread_t *uthread_create_main();
void uthread_release_all();
void main_loop();
thread_t* find_next_to_run();
void uthread_join();
void thread_routine_handler(int index);
void setup_timer_slice_out();
void thread_time_run_out(int signal);
void switch_thread();
void uthread_start();

#endif // UTHREAD_H

** uthread.c**

#include <stddef.h> // for NULL
#include <stdlib.h> // for calloc
#include <stdio.h> // fprintf
#include <string.h>
#include <assert.h>
#include <ucontext.h>
#include <signal.h>
#include <sys/time.h>
#include "uthread.h"
#include "debug.h"

static thread_t *threads[NUM_MAX_THREADS] = {0};
static volatile int threads_count = 0;
static ucontext_t main_context = {0};
static volatile int curr_thread_id = -1;

void no_memory(void)
{
    fprintf(stderr, "run out of memory!\n");
}

void thread_routine_handler(int index)
{
    debug("thread_routine_handler() got called!\n");

    thread_t *th = threads[index];
    start_routine_t start_routine = th->start_routine; 
    void *arg_routine = th->routine_arg;

    start_routine(arg_routine);

    th->state = THREAD_STATE_DONE;
}

void thread_time_run_out(int signal)
{
    switch_thread();
}

void setup_timer_slice_out()
{
    struct sigaction sa;
    sa.sa_handler = thread_time_run_out;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;
    sigaction(SIGALRM, &sa, NULL);

    struct itimerval timer;
    timer.it_value.tv_sec = 5;
    timer.it_value.tv_usec = 0;
    timer.it_interval.tv_sec = 0;
    timer.it_interval.tv_usec = 0;
    setitimer(ITIMER_REAL, &timer, NULL);
}

thread_t* create_thread_info(start_routine_t start_routine, void *arg)
{
    void *th_mem = NULL;
    void *stack_mem = NULL;

    th_mem = calloc(1, sizeof(thread_t));
    if(!th_mem)
    {
        goto failure;
    }

    stack_mem = calloc(sizeof(char), STACK_SIZE);
    if(!stack_mem)
    {
        goto failure;
    }

    if(threads_count > NUM_MAX_THREADS)
    {
        fprintf(stderr, "number max of threads reached!");
        exit(EXIT_FAILURE);
    }

    thread_t *th = th_mem;
    th->stack = stack_mem;
    th->start_routine = start_routine;
    th->routine_arg = arg;
    th->id = threads_count;
    th->state = THREAD_STATE_PENDING;
    threads[threads_count] = th;
    threads_count++;

    getcontext(&th->context);
    th->context.uc_stack.ss_sp = th->stack;
    th->context.uc_stack.ss_size = STACK_SIZE;
    th->context.uc_link = &main_context;
    makecontext(&th->context,  (void (*)())thread_routine_handler, 1, th->id);
    return th;

    failure:
        if(th_mem)
        {
            free(th_mem);
            th_mem = NULL;
        }
        if(stack_mem)
        {
            free(stack_mem);
            stack_mem = NULL;
        }
        no_memory();
        exit(EXIT_FAILURE);
}
                                                                                                                                                                                          
thread_t *uthread_create(start_routine_t start_routine, void *restrict arg)
{
    thread_t *t = create_thread_info(start_routine, arg);
    curr_thread_id = t->id;
    setup_timer_slice_out();
    swapcontext(&main_context, &t->context);
    debug("returning from create()\n");
    return t;
}

void uthread_join()
{
    debug("uthread_join() got called! \n");
    for(int i = 0; i < threads_count; i++)
    {
        thread_t *t = threads[i];
        if(t->state == THREAD_STATE_PENDING ||
           t->state == THREAD_STATE_RUNNING)
        {
            debug("got a thread to run id = %d...\n", t->id);
            swapcontext(&main_context, &t->context);
        }
    }
}

void uthread_release(thread_t **th)
{
    thread_t *p = *th;
    free(p->stack);
    p->stack = NULL;
    free(*th);
    *th = NULL;
}

thread_t* find_next_to_run()
{
    debug("find_next_to_run() got called!\n");
    debug("threads_count = %d\n", threads_count);

    for(int i = 0; i < threads_count; i++)
    {
        thread_t *t = threads[i];
        if(t->id != curr_thread_id &&
          (t->state == THREAD_STATE_PENDING ||
           t->state == THREAD_STATE_RUNNING))
        {
            return t;
        }
    }

    return NULL;
}

void switch_thread()
{
    debug("switch_thread() got called!\n");

    assert(curr_thread_id != -1);

    thread_t *to = find_next_to_run();
    if(to)
    {
        debug("switch from thread from %d to %d", curr_thread_id, to->id);
        thread_t *from = threads[curr_thread_id];
        swapcontext(&from->context, &to->context);
    }
#if 1
    else
    {
        debug("nothing to run!!\n");
    }
#endif
}

void uthread_release_all()
{
    /*
    for(int i = 0; i < threads_count; i++)
    {
        thread_t *t = threads[i];
        uthread_release(t);
    }
    */
}

主要功能:

#include <stdio.h>
#include <stdlib.h>
#include <ucontext.h>
#include <stdarg.h>
#include <assert.h>
#include <unistd.h>
#include "uthread.h"
#include "debug.h"

thread_t *thread1 = NULL, *thread2 = NULL;
ucontext_t main_context;

void thread1_function() {


    for (int i = 0; i < 10; i++) {
        printf("Thread 1 count: %d\n", i);
        if ( !thread2->done ) {
            swapcontext(&thread1->context, &thread2->context);
        }
    }

    thread1->done = 1;
    printf("Thread 1 done\n");
}

void thread2_function() {
    for (int i = 0; i < 10; i++) {
        printf("Thread 2 count: %d\n", i);
        if ( !thread1->done ) {
            swapcontext(&thread2->context, &thread1->context);
        }
    }

    printf("Thread 2 done\n");
    thread2->done = 1;
}

typedef struct Arg_type
{
    int id;
    char *s;
} Arg_t;

void test1(void *arg)
{
    printf("hello from test1()\n");

    printf("hold on...\n");
    printf("in sleep...\n");
    sleep(15);
    printf("out sleep...\n");
    
    Arg_t *a  = (Arg_t*) arg;
    printf("id = %d, message = %s\n", a->id, a->s);

    printf("exiting from test1()!\n");
}

void test2(void* arg)
{
    printf("hello from test2()\n");
    Arg_t *a  = (Arg_t*) arg;
    printf("id = %d, message = %s\n", a->id, a->s);
    printf("exiting from test2()\n");
}

int main()
{
    Arg_t a1 = {10, "foo"};
    Arg_t a2 = {20, "baa"};

    uthread_create(test1, &a1);
    uthread_create(test2, &a2);
    uthread_join();

    while(1)
    {
        printf("press 'q' to exit...\n");
        int ch = getchar();
        if(ch == 'q' || ch == 'Q') break;
    }

    debug("return from main\n");
    return 0;
    
#if 0
    thread1 = uthread_create(thread1_function, NULL);
    thread2 = uthread_create(thread2_function, NULL);

    getcontext(&thread1.context);
    thread1.context.uc_stack.ss_sp = thread1.stack;
    thread1.context.uc_stack.ss_size = STACK_SIZE;
    thread1.context.uc_link = &main_context;
    makecontext(&thread1.context, (void (*)())thread1_function, 2, 10, 20);


    getcontext(&thread2.context);
    thread2.context.uc_stack.ss_sp = thread2.stack;
    thread2.context.uc_stack.ss_size = STACK_SIZE;
    thread2.context.uc_link = &main_context;
    makecontext(&thread2.context, (void (*)())thread2_function, 0);

    swapcontext( &main_context, &thread1->context );

    if ( !thread1->done ) {
        setcontext( &thread1->context );
    }
    if ( !thread2->done ) {
        setcontext( &thread2->context );
    }

    uthread_release(&thread1);
    assert(thread1 == NULL);
    uthread_release(&thread2);
    assert(thread2 == NULL);

    return 0;

#endif
}

当 test1() 超时时调用 test2() 函数

c signals wsl-2
© www.soinside.com 2019 - 2024. All rights reserved.