警报处理程序中交换上下文后的分段错误

Posted

技术标签:

【中文标题】警报处理程序中交换上下文后的分段错误【英文标题】:Segmentation fault after swapcontext in alarm handler 【发布时间】:2013-10-13 08:00:23 【问题描述】:

基本上我想要做的是在单个线程上通过上下文切换模拟多线程。我每 10 微秒设置一次警报,然后将上下文从一个线程切换到另一个线程。问题是大约五分之一的运行在警报完成交换上下文后立即出现段错误,至少那是我用 gdb 跟踪它的地方。

这是我的源文件 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)
    
    

我尝试了很多组合并尝试通过指令进行跟踪,但无法就可能导致此段错误的原因得出结论或想法。谢谢

【问题讨论】:

【参考方案1】:

我看到的几个问题(一些与段错误和其他一些 cmets 有关)

    您的调度程序 (thread_scheduler) 应该位于临界区,例如您应该阻止任何警报信号(或忽略它们),以便线程池的处理以不会破坏它的方式完成。您可以使用 sigprocmask 或 volatile 布尔变量来使警报静音(注意这与用户线程互斥锁不同,只是与调度逻辑的内部同步)

    恕我直言,您的时钟滴答声太快了,这是以微秒为单位,而不是毫秒,因此 tv_usec 的 1000 微秒对于测试目的可能更有意义。

    较小的堆栈大小也可能导致段错误,但您的堆栈似乎足够大。

附言有一种更好的方法来处理连接,你目前在它上面浪费了大量的 CPU 周期,为什么不简单地避免切换到一个调用连接的线程,直到它正在等待的线程终止?

【讨论】:

以上是关于警报处理程序中交换上下文后的分段错误的主要内容,如果未能解决你的问题,请参考以下文章

分段错误:在 C++ 中弹出向量时出现 11

使用 lua coroutine api 和 lua_close 时出现分段错误

使用结构和指针的分段错误(核心转储)

并发编程-问题解决

EmberJS RSVP onerror 处理程序中的上下文

Perl在使用警报超时时出现分段错误