реклама на сайте
подробности

 
 
 
Reply to this topicStart new topic
> Принцип работы ОС, как?
Denisvak
сообщение Aug 21 2007, 18:47
Сообщение #1


Частый гость
**

Группа: Участник
Сообщений: 141
Регистрация: 7-03-06
Из: Санкт-Петербург
Пользователь №: 15 038



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

Вопросы:
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. большая просьба не удалять тему...поиском пользовался но ничего не нашел sad.gif
Спасибо

Сообщение отредактировал Denisvak - Aug 21 2007, 18:48
Go to the top of the page
 
+Quote Post
rezident
сообщение Aug 21 2007, 19:25
Сообщение #2


Гуру
******

Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882



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

Контекст (содержимое ОЗУ/стек/РОН, используемое каждой функцией) сохранять нужно.
Только мнится мне что для вашего случая может и не нужна эта ОС. Если критично время выполнения одного цикла суперцикла (пардон за тавталогию!), то каждую функцию можно разбить на куски таким образом, чтобы суммарное время выполнения цикла из любых кусков этих трех функций не превышало критическое для суперцикла. При вызове каждой функции она переходит по какому-то собственному флагу/счетчику на выполнение текущего куска. В конце этого куска флаг/счетчик изменяется на следующий по порядку и происходит выход с передачей управления следующей функции. При такой организации суперцикла геморроя с распределением памяти, сохранением/восстановлением контекста и детерменированностью порядка выполнения действий операций меньше, чем в случае кооперативной ОС.
Типичный пример применения суперцикла: сбор данных с АЦП, вычисления, вывод на индикацию. Что-либо вычислять до получения данных с АЦП нет смысла. Выводить на индикацию, не получив результатов расчета нечего. Для такого применения ОС не нужна, достаточно суперцикла. Причем даже если ввести обработку запросов по связи и пользовательский интерфейс, то это тоже не повод использования ОС. В большинстве случаев тот же суперцикл вполне может справиться с этой задачей. Только лишь при недостаточном быстродействии расчета блок вычислений лучше поделить на куски, чтобы не превысить таймаут, выделенный на формирование ответа по связи.
Go to the top of the page
 
+Quote Post
SamHaris
сообщение Aug 22 2007, 06:10
Сообщение #3





Группа: Новичок
Сообщений: 13
Регистрация: 11-08-05
Пользователь №: 7 546



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

Один из примеров алгоритма:
Код
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 должен быть довольно большим.
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Aug 22 2007, 08:33
Сообщение #4


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



Цитата(Denisvak @ Aug 21 2007, 21:47) *
применять какую либо готовую ОС не вижу смысла для подобной задачи...да просто хочется самому понять принцып.
Возьмите документацию и исходники какой-нибудь готовой ОС и попробуйте разобраться по ним - это будет продуктивнее, чем если кто-то будет пытаться изложить здесь всю теорию своими словами, к тому же будете иметь пример реализации перед глазами. Вот тут перечислены некоторые небольшие ОС, с которых можно начать изучение.
Кратко примерно так: существует понятие "контекст задачи" - это содержимое всех регистров (включая указатель стека) на момент прерывания задачи. Каждая задача имеет свой собственный стек, где она размещает локальные переменные, адреса возвратов и т.д. При переключении задач контекст текущей задачи сохраняется на ее стеке, указатель стека переключается на стек следующей задачи и контекст восстанавливается из стека в регистры.
Поскольку переключение контекста обычно происходит в одной и той же точке - в процедуре смены контекста, то значение счетчика команд сохранять не нужно - оно уже автоматически сохранено на стеке текущего процесса при вызове этой функции.

P.S. А насчет применять готовую - весь вопрос в потраченном времени. Ведь ничто не мешает хорошо разобраться как работает готовое и применить его, если подходит. Плюсов три:
1) Вы сэкономите время на написании с нуля.
2) В готовом ошибки ищут все, кто пользует это готовое, а в вашем коде вы будете искать их водиночку.
3) Те, кто писали готовое имеют несколько больший опыт и могли учесть в своей реализации нюансы, о которых вы и не догадываетесь, но которые в неподходящий момент вам вылезут боком.


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
Maddy
сообщение Aug 23 2007, 14:47
Сообщение #5


Участник
*

Группа: Validating
Сообщений: 56
Регистрация: 15-10-06
Пользователь №: 21 335



А самый тупой варивнт ?
Код
void Function_1(void){
}
void Function_2(void){
}
void Function_3(void){
}

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

Если не требуется жесткого квантирования времени выполнения функций - это самый простой вариант wink.gif
Go to the top of the page
 
+Quote Post
Denisvak
сообщение Aug 23 2007, 15:45
Сообщение #6


Частый гость
**

Группа: Участник
Сообщений: 141
Регистрация: 7-03-06
Из: Санкт-Петербург
Пользователь №: 15 038



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



Цитата(Maddy @ Aug 23 2007, 18:47) *
А самый тупой варивнт ?

a14.gif конечно...

Но не подходит тупой...
biggrin.gif
Go to the top of the page
 
+Quote Post
Maddy
сообщение Aug 23 2007, 18:41
Сообщение #7


Участник
*

Группа: Validating
Сообщений: 56
Регистрация: 15-10-06
Пользователь №: 21 335



а проц какой?
Go to the top of the page
 
+Quote Post
WHALE
сообщение Aug 23 2007, 18:56
Сообщение #8


Знающий
****

Группа: Свой
Сообщений: 902
Регистрация: 2-01-06
Из: Краснодар
Пользователь №: 12 768



А если чуть-чуть посложнее?
Код
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;}
}
}


--------------------
"Hello, word!" - 17 errors 56 warnings
Go to the top of the page
 
+Quote Post
SpyBot
сообщение Aug 24 2007, 09:35
Сообщение #9


Местный
***

Группа: Свой
Сообщений: 285
Регистрация: 5-11-05
Пользователь №: 10 491



Цитата(Denisvak @ Aug 23 2007, 19:45) *
Спасибо всем кто откликнулся, немного понял как и что.... smile.gif
a14.gif конечно...

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

Сорри за возможно необъективную рекламу, но мне очень понравилось описание scmRTOS v2 smile.gif
Это не только ответы на все ваши вопросы, написанные подробно и очень легким для понимания стилем, но ещё и углубление и расширение темы и примеры кода smile.gif
ну и плюс несколько ссылочек из поиска
http://www.google.ru/search?hl=ru&q=av...onix.ru&lr=
Go to the top of the page
 
+Quote Post

Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 22nd August 2025 - 21:17
Рейтинг@Mail.ru


Страница сгенерированна за 0.01429 секунд с 7
ELECTRONIX ©2004-2016