我已经设置了 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() 函数