1

基本的に私がやろうとしているのは、コンテキスト切り替えを使用して単一のスレッドでマルチスレッドをシミュレートすることです。10 マイクロ秒ごとにアラームを設定し、コンテキストをあるスレッドから別のスレッドに切り替えます。問題は、アラームがスワップコンテキストを終了した直後に、5 回に 1 回の実行でセグ フォールトが発生することです。少なくとも、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)
    {
    }
}

さまざまな組み合わせを試し、命令ごとにトレースを試みましたが、このセグ フォールトの原因についての結論や考えには至りませんでした。ありがとう

4

1 に答える 1

0

私が見た問題はほとんどありません(一部はsegfaultに関連しています+その他のコメントがあります)

  1. スケジューラ (thread_scheduler) はクリティカル セクションにある必要があります。たとえば、アラーム シグナルをブロック (または無視) して、スレッドプールが壊れないように処理する必要があります。アラームを無音にする sigprocmask または volatile ブール変数のいずれかを使用できます (これは、ユーザー スレッドのミューテックスとは異なり、スケジューリング ロジックへの内部同期に過ぎないことに注意してください)。

  2. あなたの時計は速すぎます。これはミリ秒ではなくマイクロ秒であるため、テスト目的では tv_usec の 1000 マイクロ秒の方が理にかなっている可能性があります。

  3. 小さなスタック サイズでもセグ フォールトが発生する可能性がありますが、スタックが十分に大きいようです。

ps join を処理するためのより良い方法があります。現在、多くの CPU サイクルを浪費しています。join を呼び出したスレッドへの切り替えを、待機中のスレッドが終了するまで回避しないのはなぜですか?

于 2014-01-21T16:39:24.823 に答える