c - 使用 SIGALRM 切换线程上下文

标签 c multithreading race-condition ucontext

我有一个问题。我需要实现一个使用计时器和 SIGALRM 切换 ucontext 线程的程序,但是当我使用 evict_thread 函数切换线程时出现段错误。我相信这是竞争条件的结果,因为它发生在程序执行期间的不同时间。这是我的 evict_thread

void evict_thread(int signal)
{   
// Check that there is more than one thread in the queue
if ((int)list_length(runqueue) > 1)
{
    // Remove the currently executing thread from the runqueue and store its id
    int evict_thread_id = list_shift_int(runqueue);

    // Place the thread at the back of the run queue
    list_append_int(runqueue, evict_thread_id);

    // Get the id of the thread that is now at the head of the run queue
    int exec_thread_id = list_item_int(runqueue, 0);

    // Set the start time for new thread to the current time
    clock_gettime(CLOCK_REALTIME, &thread_table[exec_thread_id]->start);

    printf("Switching context from %s to %s\n",
        thread_table[evict_thread_id]->thread_name,
        thread_table[exec_thread_id]->thread_name);

    // Execute the thread at the head of the run queue
    if (swapcontext(&thread_table[evict_thread_id]->context, &thread_table[exec_thread_id]->context) == -1)
    {
        perror("swapcontext failed\n");
        printf("errno: %d.\n", errno);
        return;
    }   
}
return;     
}

以上函数的调用方式如下

// Set the SIGALRM
if (sigset(SIGALRM, evict_thread) == -1)
{
    perror("sigset failed\n");
    printf("errno: %d.\n", errno);
    return;
}

// Initialize timer
thread_switcher.it_interval.tv_sec  = 0;
thread_switcher.it_interval.tv_usec = quantum_size;
thread_switcher.it_value.tv_sec = 0;
thread_switcher.it_value.tv_usec =  quantum_size;
setitimer(ITIMER_REAL, &thread_switcher, 0);

运行队列只是一个全局整数列表,这些整数是指向 ucontext 线程的全局指针表的索引。该列表是使用 libslack.org 上提供的 C 通用实用程序库中的列表数据结构实现的。

当我禁用计时器并让每个线程在切换上下文之前运行完成时,程序会正常运行,但是当在执行期间切换线程时,大约 80% 的时间会出现段错误。

此外,当我尝试使用 gdb 回溯段错误时,它表示它发生在系统调用内。

最佳答案

请记住,信号处理程序与主代码异步运行。 man 7 signal 页面值得仔细阅读,以确保您遵守指南。例如,在 Async-signal-safe-functions 部分中,没有提及 printf 或其他函数,例如 swapcontext。这意味着您无法从信号处理程序可靠地调用这些函数。

一般来说,尝试在信号处理程序中做尽可能少的工作。通常,这仅意味着在信号处理程序中设置 sig_atomic_t 类型的标志,然后在主循环中检查该标志的状态。

也许重新排列您的代码,以便上下文切换发生在主循环中,而不是来自信号处理程序。您也许可以在主循环中使用 sigwait 来等待计时器信号。

关于c - 使用 SIGALRM 切换线程上下文,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15398556/

相关文章:

c - C : memory leaks 中的对象方法

c - 为什么 malloc 分配的内存空间比我要求的多?

Android 后台服务类 "onStartCommand"方法在设备启动时不执行其中的所有代码

c++ - cppreference 上的错误 std::condition_variable 示例?

c# - 在循环中顺序执行函数而不阻塞ui

c++ - Valgrind 在不应该的时候报告竞争条件

multithreading - 一条汇编指令是否总是以原子方式执行?

c - 拆分字符串中的空格并将它们存储在没有库的C中的表中

c - 将第一个单词保存在c中的文件中

unit-testing - 表驱动测试中的竞争检测