gpt4 book ai didi

c - 使用 sigaction 时未调用信号处理程序

转载 作者:太空宇宙 更新时间:2023-11-04 02:51:37 27 4
gpt4 key购买 nike

我正在尝试实现一个用户级线程库,并且需要以循环方式安排线程。我目前正在尝试为我使用 makecontext、getcontext 和 swapcontext 创建的 2 个线程进行切换。使用带有 ITIMER_PROF 值的 setitimer,并为 sigaction 分配一个处理程序,以便在生成 SIGPROF 信号时安排一个新线程。但是,不会调用信号处理程序,因此永远不会安排线程。可能是什么原因?以下是部分代码片段:

    void userthread_init(long period){
/*long time_period = period;
//Includes all the code like initializing the timer and attaching the signal
// handler function "schedule()" to the signal SIGPROF.
// create a linked list of threads - each thread's context gets added to the list/updated in the list
// in userthread_create*/

struct itimerval it;
struct sigaction act;
act.sa_flags = SA_SIGINFO;
act.sa_sigaction = &schedule;
sigemptyset(&act.sa_mask);
sigaction(SIGPROF,&act,NULL);
time_period = period;
it.it_interval.tv_sec = 4;
it.it_interval.tv_usec = period;
it.it_value.tv_sec = 1;
it.it_value.tv_usec = 100000;
setitimer(ITIMER_PROF, &it,NULL);
//for(;;);
}

上面的代码是初始化一个定时器并将一个处理程序调度附加到信号处理程序。我假设信号 SIGPROF 将被提供给将调用 scheduler() 函数的上述函数。调度器函数如下:

void schedule(int sig, siginfo_t *siginf, ucontext_t* context1){
printf("\nIn schedule");
ucontext_t *ucp = NULL;
ucp = malloc(sizeof(ucontext_t));
getcontext(ucp);
//ucp = &sched->context;
sched->context = *context1;
if(sched->next != NULL){

sched = sched->next;
}
else{
sched = first;
}
setcontext(&sched->context);
}

我有一个就绪线程队列,其中存储了它们各自的上下文。每当执行 setcontext 指令时,每个线程都应该得到调度。但是,不会调用 scheduler()!谁能指出我的错误??

最佳答案

看完代码后彻底修改这个答案。有几个问题:

  • 有几个编译器警告
  • 您永远不会初始化您的线程 ID,无论是在线程创建方法的外部还是内部,所以我很惊讶代码竟然能工作!
  • 您正在 gtthread_create() 函数中读取未初始化的内存,我在 OSX 和 Linux 上都进行了测试,在 OSX 上它崩溃了,在 Linux 上奇迹般地它被初始化了。
  • 在某些地方你调用 malloc(),并用指向其他东西的指针覆盖它——泄漏内存
  • 您的线程在完成后不会从链表中删除自己,因此例程完成后会发生奇怪的事情。

当我在 while(1) 循环中添加时,我确实看到 schedule() 被调用并从线程 2 输出,但线程 1 消失得无影无踪(可能是因为线程 ID 未初始化)。我认为您需要进行大量代码清理。

这是我的建议:

  • 修复所有编译器警告 — 即使您认为它们无关紧要,噪音也可能导致您遗漏一些东西(例如不兼容的指针类型等)。您正在使用 -Wall & -pedantic; 进行编译;这是一件好事 - 所以现在采取下一步并修复它们。
  • 将\n 放在 printf 语句的末尾,而不是开头 — 这两个线程正在输出到标准输出,但它没有被刷新,因此您看不到它。将 printf("\nMessage"); 调用更改为 printf("Message\n");
  • 使用 Valgrind检测内存问题 — valgrind 是您将用于 C/C++ 开发的最神奇的工具。它可以通过 apt-get 和 yum 获得。不要运行 ./test1,而是运行 valgrind ./test1,它会突出显示内存损坏、内存泄漏、未初始化的读取等。我怎么强调都不为过; Valgrind 很棒。
  • 如果系统调用返回一个值,检查它 — 在您的代码中,检查所有 getcontext、swapcontext、sigaction、setitimer 的返回值
  • 仅从您的调度程序调用异步信号安全方法(或任何信号处理程序)— 到目前为止,您已经从调度程序内部修复了 malloc() 和 printf()。查看the signal(7) man page - 参见“异步信号安全函数”
  • 模块化你的代码——你的链表实现可能更整洁,如果它被分离出来,那么 1) 你的调度程序将有更少的代码并且更简单,并且 2) 你可以隔离问题您的链接列表,而无需调试调度程序代码。

了,所以坚持下去 - 但请牢记这三个简单的规则:

  1. 边走边打扫
  2. 修复编译器警告
  3. 当奇怪的事情发生时,使用 valgrind

祝你好运!


旧答案:

您应该检查任何系统调用的返回值。无论它是否能帮助您找到答案,您都应该这样做:)

检查sigaction()的返回值,如果是-1,检查errno。 sigaction() 可能因某些原因而失败。如果您的信号处理程序未被触发,则可能尚未设置。

编辑:并确保您也检查了 setitimer() 的返回值!

编辑 2:只是一个想法,您可以尝试摆脱 malloc() 吗? malloc 不是信号安全的。例如:像这样:

void schedule(int sig, siginfo_t *siginf, ucontext_t* context1){
printf("In schedule\n");
getcontext(&sched->context);
if(sched->next != NULL){
sched = sched->next;
}
else{
sched = first;
}
setcontext(&sched->context);
}

编辑 3:根据 this discussion ,您不能在信号处理程序中使用 printf()。您可以尝试将其替换为对 write() 的调用,这异步信号安全的:

// printf("In schedule\n");
const char message[] = "In schedule\n";
write( 1, message, sizeof( message ) );

关于c - 使用 sigaction 时未调用信号处理程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21520461/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com