Перейти к содержанию
    

Принцип работы ОС

Добрый вечер.

Задача примерно такая...

Есть две-три функции которые крутятся в бесконечном цыкле - необходимо чтобы они выполнялись как бы паралельно, и процессорное время было поделено между ними поровну. Хочу разобраться как работают ОС и написать свой код для этого...применять какую либо готовую ОС не вижу смысла для подобной задачи...да просто хочется самому понять принцып.

 

Вопросы:

1.Есть код...те самые три функции...

void Function_1(void){
    for(;;){
    ..............
    }
}
void Function_2(void){
    for(;;){
    ..............
    }
}
void Function_3(void){
    for(;;){
    ..............
    }
}

 

как делить между ними процессорное время? Так понимаю что таймером...но вот к примеру таймер сработал когда "мы" находились в середине функции Function_1...выполнение прервалось и перешли к Function_2...Function_3....дальше возвращаемся в Function_1. Но вот как узнать на каком участке кода "мы" прервали функцию и откуда надо продолжить её выполнение?

 

 

 

P.S. большая просьба не удалять тему...поиском пользовался но ничего не нашел :(

Спасибо

Изменено пользователем Denisvak

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Но вот как узнать на каком участке кода "мы" прервали функцию и откуда надо продолжить её выполнение?

Контекст (содержимое ОЗУ/стек/РОН, используемое каждой функцией) сохранять нужно.

Только мнится мне что для вашего случая может и не нужна эта ОС. Если критично время выполнения одного цикла суперцикла (пардон за тавталогию!), то каждую функцию можно разбить на куски таким образом, чтобы суммарное время выполнения цикла из любых кусков этих трех функций не превышало критическое для суперцикла. При вызове каждой функции она переходит по какому-то собственному флагу/счетчику на выполнение текущего куска. В конце этого куска флаг/счетчик изменяется на следующий по порядку и происходит выход с передачей управления следующей функции. При такой организации суперцикла геморроя с распределением памяти, сохранением/восстановлением контекста и детерменированностью порядка выполнения действий операций меньше, чем в случае кооперативной ОС.

Типичный пример применения суперцикла: сбор данных с АЦП, вычисления, вывод на индикацию. Что-либо вычислять до получения данных с АЦП нет смысла. Выводить на индикацию, не получив результатов расчета нечего. Для такого применения ОС не нужна, достаточно суперцикла. Причем даже если ввести обработку запросов по связи и пользовательский интерфейс, то это тоже не повод использования ОС. В большинстве случаев тот же суперцикл вполне может справиться с этой задачей. Только лишь при недостаточном быстродействии расчета блок вычислений лучше поделить на куски, чтобы не превысить таймаут, выделенный на формирование ответа по связи.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Можешь использовать для этого случая стек. При истечения таймера делаешь подмену в стеке адрес возврата. Но это накладывает свои ограничения на локальные переменные. Тобишь лучше от них вообще отказатся, или выделить их в глобальные или статические, или при подмене адреса в стеке меняешь и сам стек (Вариантов куча).

 

Один из примеров алгоритма:

int g_Func;
void *StackAdress;
TStackFunc StackFunc[3];

Main() {
    StackAdress = <текущее значение стека>
    g_Func = -1; Func1();
    g_Func--; Func2(); 
    g_Func--; Func3();
    g_Func = 0;
    Func1();
}
Func1 () {
    While(1) {
        Timer();
        ...
        Timer();
        ...
        Timer();
    }
}
Func2 () {
    // Аналогично как в Func1()
}
Func3 () {
    // Аналогично как в Func1()
}
Timer() {
    if (g_Func < 0) { // Инициализация
        StackFunc[-g_Func + 1] = <сохраняем стек от текущего значение стека до StackAdress>;
        <адрес возврата в стеке> = <адрес возврата в функцию Main>;
        return;
    }
    if (<Таймер не истек>) return;
    StackFunc[g_Func] = <записывавем стека от текущего значение стека до StackAdress>;
    g_Func++; 
    if (g_Func > 3) g_Func = 0;
    <востанавливаем стек от текущего значение стека до StackAdress> = StackFunc[g_Func];
}

 

 

Опять же на поминаю про локальные переменные и вызов других функций, они тоже занимают место в стеке. Тобишь тип TStackFunc должен быть довольно большим.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

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

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

 

P.S. А насчет применять готовую - весь вопрос в потраченном времени. Ведь ничто не мешает хорошо разобраться как работает готовое и применить его, если подходит. Плюсов три:

1) Вы сэкономите время на написании с нуля.

2) В готовом ошибки ищут все, кто пользует это готовое, а в вашем коде вы будете искать их водиночку.

3) Те, кто писали готовое имеют несколько больший опыт и могли учесть в своей реализации нюансы, о которых вы и не догадываетесь, но которые в неподходящий момент вам вылезут боком.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Гость Maddy

А самый тупой варивнт ?

void Function_1(void){
}
void Function_2(void){
}
void Function_3(void){
}

void run(void)
{
for(;;)
{
  Function_1();
  Function_2();
  Function_3();
}
}

Если не требуется жесткого квантирования времени выполнения функций - это самый простой вариант ;)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Спасибо всем кто откликнулся, немного понял как и что.... :)

 

 

 

А самый тупой варивнт ?

:a14: конечно...

 

Но не подходит тупой...

:biggrin:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А если чуть-чуть посложнее?

void Function_1(void){
....
if(abcd) request_handling_Function_1=1;
}
void Function_2(void){
....
if(bcda) request_handling_Function_2=1;
}
void Function_3(void){
....
if(cdab) request_handling_Function_3=1;
}

void run(void)
{
for(;;)
{
  if(request_handling_Function_1){Function_1();request_handling_Function_1=0;}
  if(request_handling_Function_2){Function_2();request_handling_Function_2=0;}
  if(request_handling_Function_3){Function_3();request_handling_Function_3=0;}
}
}

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Спасибо всем кто откликнулся, немного понял как и что.... :)

:a14: конечно...

 

Но не подходит тупой...

:biggrin:

Сорри за возможно необъективную рекламу, но мне очень понравилось описание scmRTOS v2 :)

Это не только ответы на все ваши вопросы, написанные подробно и очень легким для понимания стилем, но ещё и углубление и расширение темы и примеры кода :)

ну и плюс несколько ссылочек из поиска

http://www.google.ru/search?hl=ru&q=av...onix.ru&lr=

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

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

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...