2013-10-06 72 views
1

基本上我正在尝试的是在具有上下文切换的单个线程上模拟多线程。我每10微秒设置一次闹钟,并将上下文从一个切换到另一个线程。问题在于,大约有五分之一的运行结束时会在报警完成swapcontext后发生seg故障,至少这是我用gdb跟踪它的地方。报警处理程序中的swapcontext之后的分段错误

这里是我的源文件 main.c中

#include "umt.h" 

void f() 
{ 
    int x = 10; 
    printf("starting thread\n"); 
    while(x) 
    { 
     printf("thread %d\n", x); 
     sleep(1); 
     x--; 
    } 

} 

int main() 
{ 
    int x = 0, y, z; 
    umt_init(); 
    y = umt_thread_create(f); 
    printf("starting main\n"); 
    if(y == 0) 
    { 
     printf("Problems with creating thread\n"); 
     return; 
    } 
    x = 10; 
    z = 1; 
    while(x) 
    { 
     printf("main\n"); 
     x--; 
    } 
    umt_thread_join(y); 
    printf("done waiting\n"); 
    return 0; 
} 

UMT.h

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

#define TRUE  1 
#define FALSE  0 

typedef struct _umt_thread 
{ 
    int thread_id; 
    ucontext_t context; 
    void (*handler)(void); 
    int hasFinished; 
}umt_thread, *pumt_thread; 

void umt_init(); 

int umt_thread_create(void (*handler)(void)); 

void umt_thread_join(int thr); 

和umt.c

#include "umt.h" 

#define MAIN_CONTEXT  0 
#define STACK_SIZE   1638400 

int currentThread; 
char threadpool[15]; 

pumt_thread threads; 

void signal_thread_finish(); 

void thread_handler() 
{ 
    threads[currentThread].handler(); 
    signal_thread_finish(); 
} 

void thread_scheduler(); 

void signal_thread_finish() 
{ 
    threads[currentThread].hasFinished = TRUE; 
    threadpool[currentThread] = 0; 
    thread_scheduler(); 
} 

void thread_scheduler() 
{ 
    int nextThread = 0, curThread = 0; 
    int x = 0; 
    ucontext_t *con1, *con2; 

    nextThread = currentThread + 1; 
    while(1) 
    { 
     if(nextThread == 15) 
      nextThread = 0; 
     if(nextThread == currentThread) 
      break; 
     if(threadpool[nextThread] == 1) 
      break; 
     nextThread++; 
    } 

    if(nextThread == currentThread) 
     return; 
    curThread = currentThread; 
    currentThread = nextThread; 
    con1 = &(threads[curThread].context); 
    con2 = &(threads[nextThread].context); 
    x = swapcontext(con1, con2); 
} 

void umt_init() 
{ 
    ucontext_t context; 
    struct itimerval mytimer; 
    int i; 
    stack_t new_stack; 

    getcontext(&context); 

    threads = (pumt_thread)malloc(sizeof(umt_thread) * 15); 
    threads[MAIN_CONTEXT].thread_id = MAIN_CONTEXT; 
    threads[MAIN_CONTEXT].context = context; 

    threadpool[MAIN_CONTEXT] = 1; 
    for(i = 1;i<15;i++) 
    { 
     threadpool[i] = 0; 
    } 

    currentThread = 0; 

    new_stack.ss_sp = (char*)malloc(STACK_SIZE); 
    new_stack.ss_size = STACK_SIZE; 
    new_stack.ss_flags = 0; 
    i = sigaltstack(&new_stack, NULL); 
    if(i != 0) 
    { 
     printf("problems assigning new stack for signaling\n"); 
    } 

    signal(SIGALRM, thread_scheduler); 
    mytimer.it_interval.tv_sec = 0; 
    mytimer.it_interval.tv_usec = 10; 
    mytimer.it_value.tv_sec = 0; 
    mytimer.it_value.tv_usec = 5; 
    setitimer(ITIMER_REAL, &mytimer, 0); 
} 

int umt_thread_create(void (*handler)(void)) 
{ 
    ucontext_t context; 
    int i, pos; 

    for(i = 1;i<15;i++) 
    { 
     if(threadpool[i] == 0) 
     { 
      pos = i; 
      break; 
     } 
    } 
    if(i == 15) 
    { 
     printf("No empty space in the threadpool\n"); 
     return -1; 
    } 

    if(getcontext(&context) == -1) 
    { 
     printf("Problems getting context\n"); 
     return 0; 
    } 
    context.uc_link = 0;//&(threads[MAIN_CONTEXT].context); 
    context.uc_stack.ss_sp = (char*)malloc(STACK_SIZE); 
    if(context.uc_stack.ss_sp == NULL) 
    { 
     printf("Problems with allocating stack\n"); 
    } 
    context.uc_stack.ss_size = STACK_SIZE; 
    context.uc_stack.ss_flags = 0; 
    makecontext(&context, thread_handler, 0); 

    threads[pos].thread_id = pos; 
    threads[pos].context = context; 
    threads[pos].handler = handler; 
    threads[pos].hasFinished = FALSE; 

    threadpool[pos] = 1; 

    printf("Created thread on pos %d\n", pos); 

    return pos; 
} 

void umt_thread_join(int tid) 
{ 
    while(!threads[tid].hasFinished) 
    { 
    } 
} 

我尝试了很多组合,并试图追踪通过指令,但不能得出一个结论或想法,以什么可能会导致此seg错误。由于

回答

0

很少有什么问题我看到的(有些是到段错误有关+其他一些评论)

  1. 您调度(thread_scheduler)应该是一个关键部分,如您应该阻止任何报警信号(或忽略它们),以便线程池的处理以不会破坏线程池的方式完成。你可以使用sigprocmask或一个易变的布尔变量来消除报警(注意这与用户线程互斥不一样,只是内部同步到你的调度逻辑)

  2. 你的时钟滴答的方式太快恕我直言,这是微秒,而不是毫秒,所以tv_usec的1000微秒可能对测试更有意义。

  3. 小堆栈大小也可能导致seg故障,但看起来你的堆栈足够大。

p.s.有一种更好的方式来处理连接,你现在已经浪费了大量的CPU周期,为什么不简单地切换到一个称为连接的线程,直到它所等待的线程终止?