Разработайте структуры данных (контекст процесса и др.), определите необходимые системные вызовы (переключение контекста, завершение процесса и др.) и напишите функцию-планировщик процессорного времени, которая реализует дисциплину планирования FB с периодами обслуживания очередей, которые задаются их номерами. (Выход из планировщика должен выполняться только системным вызовом переключения контекста switch_context).
Контекст процесса должен содержать информацию о процессе, а именно: идентификатор процесса, данные про выделенную процессу оперативную память, об открытых файлах, и информацию, которая используется планировщиком процессорного времени.
В нашем случае для каждого процесса необходимо сохранять данные о количестве раз, которые процесс выполнялся в одной очереди.
Для реализации переключения контекста необходимо использовать системный вызов типа switch_context. Реализация этого вызова должна быть языком ассемблера, так как он делает не так как обычные функции в языках программирования высокого уровня. При завершении работы этой функции выполняется возвращение не в вызывающую функцию, а в новую – избранный процесс для работы.
Для того, чтобы реализовать планировщик процессорного времени, необходимо также определить события в системе, по которые он вызывается. Изберем следующие типы событий: уступка нового процесса на выполнение, завершения процесса, событие от таймера.
Пусть эти события имеют обозначение: NEW, EOJ, TMR.
Очереди готовых процессов описываются следующим образом:
struct QUEUE {
process *PR; //указатель на контекст процесса
unsigned long num; //счетчик количества раз выполнения
struct QUEUE *next; //указатель на следующий элемент очереди
}
в системе должно поддерживаться такое количество очередей, которое равняется количеству очередей дисциплины планировщика FB.
Составим функцию планировщика процессорного времени на псевдоязыке, синтаксис которого близок к языку программирования С. Параметрами вызова функции является событие в системе, по которому была вызвана функция, и указатель на процесс, с которым связан вызов.
Начальное состояние работы –
next – процесс, который является активным при старте системы
N – количество очередей
QUEUE[..] - массив из N очередей
NUMB – количество раз, которое может становиться процесс активным в одной очереди, при достижении этого числа процесс перемещается в очередь с большим номером с помощью внешней функции move_process
tick – переменная, хранящая время, на протяжении которого обслуживается заданная очередь
Текст программы:
function _planning_(event EVENT, process *PROCESS)
{
switch(EVENT){
case(NEW): add_process(QUEUE[1], PROCESS);break; //добавить процесс
//в первую очередь
case(EOJ): for(int I=1;I<=N;I++) //цикл прохода по очередям
{
if(QUEUE[I]!=NULL) break; //ищем первую не свободную очередь
}
next=QUEUE[I].process;break; //выбираем следующим процессом для
//выполнения первый процесс в найденной очереди
case(TMR): next.num++; if (next.num==NUMB) move_process(I,I+1);
//если процесс
//использовал все разы на выполнение в очереди,
//то переместить его
//в очередь с большим номером
tick++; if(tick==I) select_next_QUEUE(I); //если очередь уже
//обслуживалась I раз, то переключаемся на другую
//при достижении максимальной очереди переключаемся
//на очередь с минимальным номером
for(int I=1;I<=N;I++)
{
if(QUEUE[I]!=NULL) break;
}
next=QUEUE[I].process;
break;
Уважаемый посетитель!
Чтобы распечатать файл, скачайте его (в формате Word).
Ссылка на скачивание - внизу страницы.