r5 (1123694), страница 2
Текст из файла (страница 2)
Lam, Mju, Nju - параметры потоков поступления, обслуживания и выхода из очереди необслуженных
требований;
Т - максимальная продолжительность одной реализации модели;
А - рабочая переменная для поиска адреса элемента списка;
Z - рабочая переменная для поиска по времени поступления в очередь.
Начало программы может быть следующим:
program Example2 (input, output);
const
Demand = 1; {Событие поступления требования}
Service = 2; {Событие обслуживания требования}
Failure = 3; {Событие необслуживания требования}
Poisson =2; {Идентификатор пуассоновского потока}
type %include ‘type.pss’ ;
DataType = real;
var %include ‘var.pss’ ;
L, N, M, S: integer; Lam, Mju, Nju, T, Z: real; A: NotePntr;
%include ‘proc.pss’ ;
begin
Initiate;
writeln (‘ Ввод исходных данных системы массового обслуживания:’);
write (‘ Каналов обслуживания =’); readln (N);
write (‘ Параметр потока поступлен. заявок =’); readln (Lam);
write (‘ Параметр потока обслужив. заявок =’); readln (Mju);
write (‘ Параметр потока прохождения очереди =’) readln (Nju);
write (‘ Продолжительность модели =’) readln (T);
write (‘ Количество заявок во входном потоке =’) readln (M);
write (‘ Количество реализаций модели =’) readln (L);
S: =0;
Statistics ( Demand ); Statistics ( Service ); Statistics ( Failure );
Здесь производится описание номеров событий, которые могут иметь место в модели, в виде констант с названиями события:
Demand - заявка, требование; Service - обслуживание; Failure - отказ. Для организации входного потока использована константа Poisson - Пуассон. Описан тип данных, используемых для хранения времени и необходимые перемены.
Операторами %include ... в соответствии с правилами Паскаля в определенных разделах программы производится подключение соответствующих фрагментов на PSS-библиотеки.
Оператор Initiate устанавливает системные переменные в исходное состояние, которое может быть впоследствии изменено, например: переменной Inform может быть присвоено значение, определяющее вид выводимой информации и остановы программы для этапа отладки; переменная RDN_INT может быть установлена так, чтобы изменилась исходная последовательность генератора ПСЧ.
Затем производится серия запросов и ввода исходных значений переменных модели.
В переменной S будем накапливать на каждый момент появления на входе системы очередного требования количество каналов, занятых обслуживанием, для того чтобы впоследствии усреднить эту величину по количеству пришедших требований.
Последние операторы назначают сбор статистических данных для всех типов событий в модели.
Управляющий алгоритм модели имеет следующий вид:
repeat
Generate (Demand, Poisson, Lam, O, M); {Установка генерации потока}
Start (Demand, NegExp (Lam), nil, T); {Установка первой заявки}
while Simulate do case ActNumb of
Demand: <программа обработки>;
Service: <программа обработки>;
Failure: <программа обработки>;
end;
until Repeater = L;
Программа обработки события Demand - поступления требования:
Demand: begin S:=S+Have(Service); {Суммируем количества требований}
{находящихся на обслуживании, то}
{есть количество занятых каналов}
if Have (Service) < N {Если заняты не все каналы,}
then Prepare (Service, NegExp (Mju), nil) {тогда ставим}
{требование на обработку}
else {В противном случае}
begin New (Addr); {динамически создаем данные,}
Addr^ := ActTime; {помещаем в них текущее время,}
Prepare (Failure, NegExp(Nju), Addr) {ставим в очередь}
end
end;
Для создания в памяти данных здесь используется вспомогательная переменная Addr - адрес данных, Addr^ - обращение к содержимому данных.
Программа обработки события Service - требование обслужено:
Service: if Have (Failure) > 0 then {Если в очереди что-то есть}
begin {то ищем в управляющем списке}
Route:=Node; {начиная с головы,}
A:=nil; Z:=0; {присвоив начальный адрес и время,}
repeat Route:=Route^.Prev; {в сторону уменьш-я времени.}
if Route^.Numb=Failure then {Если это событие - очередь}
if Route^.Addr^ > Z then {и время поступления туда}
{более позднее, чем отслеживаемое в Z, тогда}
begin A:=Route; Z:=Route^.Addr^ end {запоминаем}
{адрес события и время его поступления в очередь}
until Route=Node; {пока не закончится список.}
Addr:=Cancel (A); {Уничтожим событие в списке и}
Dispose (Addr); {его данные.}
Prepare (Service, NegExp (Mju), nil) {Подготовим событие}
{обслуживания требования.}
end;
В начале поиска вспомогательной переменной Route присваивается адрес головы списка, а затем, при поиске нужного элемента списка этот адрес продвигается: Route:=Route^.Prev . Для прохода по списку выбрано движение в сторону уменьшения времени, но это не обязательно, так как проверяется весь список. В проверке использована конструкция if (..) then if (..) then .. поскольку, в данном случае нельзя применить сложную логическую проверку типа: if (..) and (..) then .. , из-за того, что данные можно анализировать только тогда, когда они существуют.
После прохода по списку (до головы) в А обязательно содержится адрес того события, которое относится к очереди и имеет максимальное время в своих данных. С помощью оператора Cancel данное событие из списка удаляется, а в Addr передается ссылка на данные, которые тоже удаляются из памяти оператором Dispose.
Затем, поскольку требование из системы не исчезло, а было взято на обслуживание освободившимся каналом, мы формируем событие обслуживания.
Программа обработки события Failure - выход без обслуживания:
Failure: Dispose (ActAddr); {Уничтожим данные этого события}
Окончание программы имеет вид:
writeln (‘============ Результаты моделирования ============’);
writeln (‘Вероятность обслуживания каналами =’ ,
Done (Service) / (Done (Service)+Done (Failure)): 8: 3);
writeln (‘Вероятность прохождения очереди =’ ,
Done (Service) / (Done (Service)+Done (Failure)): 8: 3);
writeln (‘Среднее число занятых каналов =’ ,
S/Repeater/Done (Demand): 8: 3);
end.
Оператор Done возвращает значение соответствующего счетчика статистической информации поделенное на количество проведенных реализаций (усредненное), поэтому применять их следует после окончания моделирования. В связи с этим же при подсчете среднего числа занятых каналов необходимо ввести деление на Repeater накопленного значения в S.
УЧЕБНЫЙ ВОПРОС 4
Пример использования PSS для моделирования системы массового обслуживания с ограничением очереди по времени ожидания и по длине.
Данную задачу предлагается решить на занятии самостоятельно, например в виде контрольной работы. Фактически требуется только написать программу деятельности отработки события поступления в систему требования. Логика программы изменится в плане необходимости проведения еще одной проверки перед формированием события постановки в очередь. Теперь, если все каналы заняты, нужно убедиться, что в очереди еще есть свободное место. Для этой проверки можно использовать оператор Have. Для хранения максимального количества заявок в очереди объявим переменную М 0 .
Demand: begin S:=S+Have (Service); {Суммируем количества требований}
{находящихся на обслуживании, то}
{есть количество занятых каналов.}
if Have (Service) < N {Если не заняты все каналы,}
then Prepare (Service, NegExp (Mju), nil){тогда ставим}
{требование на обработку}
else {В противном случае,}
Have (Failure) if < М 0 then {если очередь не заполнена, то}
begin New (Addr); {динамически создаем данные,}
Addr^ := ActTime; {помещаем в них текущее время,}
Prepare (Failure, NegExp (Nju), Addr) {ставим в очередь}
end
end;
При выводе результата следует учесть те заявки, которые не попали ни на обслуживание, ни в очередь:
writeln (‘Вероятность обслуживания каналами =’ ,
Done (Service) / Done (Demand): 8: 3);
writeln (‘Вероятность прохождения очереди =’ ,
Prep (Failure) / Done (Demand): 8: 3);
Для усложнения задания можно потребовать в качестве результата вывести вероятность того, что очередь занята:
writeln (‘Вероятность занятости очереди =’ ,
(1 - ( Prep (Failure) + Prep (Service) ) / Done (Demand) ): 8: 3);
Методическую разработку составил п/п-к Липовенко А.Г.
Методическое пособие доработано
Подполковник Швыдков С.А