【问题标题】:C Signal timer for task switchingC 任务切换信号定时器
【发布时间】:2019-05-26 07:19:00
【问题描述】:

我正在构建一个简单的任务切换器,它在循环中运行两个函数。这个想法是它运行 f1 一段时间,然后将控制权交给 f2 相同的数量,然后是 f1,f2,在一个无限循环中。

问题是,每当我运行程序时,第一个开关运行良好,但随后的开关从未发生。卡在f2。

我尝试过其他实现最多归档 3 个开关(之后程序会冻结)。

这是我当前的实现:

#include <stdio.h>
#include <signal.h>
#include <sys/time.h>
#include <unistd.h>

int count = 0;
int flag  = 0;

void f1() {
    for (;;) printf("A");
}

void f2() {
    for (;;) printf("B");
}

void sched() {
    flag = !flag;
    if (flag)
        f1();
    else
        f2();
}

void sighandler(int signo)
{
 printf("signal %d occurred %d times\n",signo, ++count);
 sched();
}

int main(void)
{
 struct itimerval it;
 struct sigaction act, oact;
 act.sa_handler = sighandler;
 sigemptyset(&act.sa_mask);
 act.sa_flags = 0;

 sigaction(SIGPROF, &act, &oact); 

 it.it_interval.tv_sec = 0;
 it.it_interval.tv_usec = 10000;
 it.it_value.tv_sec = 0;
 it.it_value.tv_usec = 10000;
 setitimer(ITIMER_PROF, &it, NULL);

 sched();
}

任何建议将不胜感激。

【问题讨论】:

  • 您正在从信号处理程序中调用代码并且永远不会从处理程序返回。并允许它(递归)再次被中断。此外,您不应在信号处理程序中调用 printf()。
  • 您可以通过在sigaction() 中设置SA_NODEFER 来使其工作(简单地说,未定义的行为丰富)。
  • 我会采取另一条路线来解决这个问题:当使用 SA_SIGINFO 提供带有刚刚中断的上下文的 ucontext_t 结构时,您的信号处理程序会获得第三个参数。您可以使用setcontext 在两个(或更多)保存的上下文之间切换,以使结果更接近真正的抢占式调度。

标签: c multithreading timer signals


【解决方案1】:

您的信号处理程序调用sched(),它永远不会返回(但会在for (;;) 循环中的任何一个中结束)。所以在第一次切换之后,你总是在信号处理程序内部,并且进一步的信号被屏蔽了。

【讨论】:

    【解决方案2】:

    尽管你已经得到了很好的答案

    您的信号处理程序调用 sched(),它永远不会返回(但最终会出现在 for (;;) 中的任何一个中...

    您的多任务实现的问题在于,要使任务切换器工作,您需要进行上下文切换。上下文切换器是一个例程,在它完成所有上下文切换到其他进程并且要安排的下一个任务是要返回的任务之前,它不会返回。这是召唤之王

    yield();
    

    但实际的上下文切换发生在 inside 的 yield。上下文切换是不能作为简单例程(您调用并返回的一段代码)实现的,因为它必须返回在另一个上下文中。为此,您需要调用 yield() 并且 yield 代码必须将所有 cpu 寄存器更改为它们在 other 上下文中的值(包括堆栈指针,所以这使您预约'将需要 两个 堆栈)然后继续执行该代码(这将使程序返回 在另一个上下文中

    因此,您需要有一些地方来存储您将允许并行运行的所有任务的上下文。这包括 cpu 状态和任务的堆栈。然后,您需要一个例程(这是实际的上下文切换),将旧上下文(cpu 正在使用的上下文)存储在保存存储中,并调用(并安装)要调度的新任务的上下文。比如:

    void task_switch(struct context *old_ctx, struct context *new_ctx);
    

    并且这个例程必须用汇编程序编写......因为它必须进行上下文切换,包括切换每个任务的堆栈。

    你现在怎么看?

    【讨论】:

    • 是的,这只是一个简化的例子,我有上下文切换模块工作(我已经完成了一个运行 4M 线程的整个线程库,没有任何问题)。现在我想让它们抢先,所以我正在研究信号实现。那是我的问题来自。无论如何,谢谢你的回答路易斯!!
    • 那么问题是一个线程消耗了整个事情......你永远不会回到调度程序......你无法启动第二个进程,因为你只有一个堆栈。跨度>
    • @LuisColorado 只要分配更多的堆栈,那么你就有很多堆栈。这不是问题。
    • @Ctx,这里的问题是信号处理程序调用切换器,切换器选择一个任务,永远不会返回。所以程序坚持到永远不会返回的信号处理程序中。他只有一个任务,因为他从未为另一个任务分配第二个堆栈,并且不进行上下文交换......在这些前提下,不再有两个任务......只有信号处理程序内的无限循环.
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-07-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-08
    • 1970-01-01
    • 2019-06-11
    相关资源
    最近更新 更多