C Таймер сигнала для переключения задач - PullRequest
0 голосов
/ 28 декабря 2018

Я создаю простой переключатель задач, который запускает две функции в цикле.Идея состоит в том, что он запускает 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();
}

Любое предложение будетс благодарностью.

Ответы [ 2 ]

0 голосов
/ 29 декабря 2018

Несмотря на то, что вам уже ответили с хорошим ответом

Ваш обработчик сигнала вызывает sched (), который никогда не возвращается (но заканчивается в любом из for (;;)...

проблема с вашей многозадачной реализацией заключается в том, что для работы переключателя задач необходимо выполнить переключение контекста. Переключатель контекста - это процедура, которая не возвращается, пока не выполнит весь контекстпереключается на другие процессы, и следующая задача, которая должна быть запланирована, должна быть возвращена.Это некий король вызова

yield();

, но фактическое переключение контекста происходит внутри yield.switch - это то, что не может быть реализовано в виде простой подпрограммы (некоторый фрагмент кода, который вы вызываете и возвращаете), потому что он должен возвращать в другом контексте . Для этого вам нужно вызвать yield() и кодyield должен изменить все регистры процессора на значения, которые они имели в контексте other (включая указатель стека, так что это назначение, которое выВам потребуется два стека), а затем продолжить выполнение этого кода (что заставит программу вернуть в другом контексте )

Так что вам нужно найти местохранить контексты всех задач, которые вы собираетесь разрешить выполнять параллельно.Это включает в себя состояние процессора и стек задачи.Затем вам нужна подпрограмма (это то, что фактически переключает контекст), которая хранит старый контекст (тот, который использует процессор) в хранилище сохранения и вызывает (и устанавливает) контексты новой задачи, которая должна быть запланирована.Что-то вроде:

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

и эта подпрограмма должна быть написана на ассемблере .... как она должна делать переключение контекста, которое включает в себя переключение стеков каждой задачи.

Как вы видитеэто сейчас?

0 голосов
/ 28 декабря 2018

Ваш обработчик сигнала вызывает sched(), который никогда не возвращается (но заканчивается в любом из циклов for (;;)).Поэтому после первого переключения вы всегда находитесь внутри обработчика сигналов, а дальнейшие сигналы маскируются.

...