Будь умным!


У вас вопросы?
У нас ответы:) SamZan.net

Вариант 9

Работа добавлена на сайт samzan.net:


ФЕДЕРАЛЬНОЕ АГЕНТСТВО СВЯЗИ

Сибирский государственный университет

телекоммуникаций и информатики.

Межрегиональный центр переподготовки специалистов

КУРСОВАЯ РАБОТА

по дисциплине

«Операционные системы»

Вариант 9

 

   

                                                              Выполнил: студент группы

                                                                                                       

                                                                                       

                                                                         

2010


Задание
.

Необходимо написать программу, реализующую параллельную работу нескольких процессов. Каждый процесс может состоять из одного или нескольких потоков. Любой из потоков, работающих в составе этих процессов, может быть приостановлен и вновь запущен некоторой определенной клавишей (можно использовать буквенные или цифровые клавиши). Нажатия клавиш обрабатывать с помощью прерывания от клавиатуры (по материалам лаб. работы №1).

Окончание работы программы должно происходить при приостановке всех потоков их ключевыми клавишами либо при нажатии клавиши ESC. При окончании работы необходимо выполнить корректное завершение, т.е. “дочитать” всю информацию из буфера каждого процесса (при его наличии), закрыть все открытые файлы и т.п. – по материалам лаб. работы №4.

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

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

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

Задачи 1, 3, 6 предполагают наличие управляющего блока, который, используя прерывания таймера, случайным образом определяет очередной активный поток и выделяет ему кванты времени (возможно, в рамках большего кванта, выделенного всему процессу). Кванты времени – как для процесса в целом, так и для его потоков – изначально задавать некоторой фиксированной величины, но предусмотреть возможность её изменения во время работы путем нажатия некоторых ключевых клавиш (для каждого из потоков предусмотреть свою клавишу) – т.е. можно, например, увеличить или уменьшить квант только потока-пpоизводителя. При этом допустимы разные варианты реализации – “общий” квант может либо меняться, либо оставаться постоянным (тогда при ускорении одного потока другой автоматически замедлится, т.к. величина его кванта уменьшится).

Потоки этого класса задач могут иметь три статуса: “активен”, “ожидает” или “приостановлен”. В процессе работы может возникнуть, например, следующая ситуация. Поток-потребитель приостановлен своей ключевой клавишей, следовательно, буфер не освобождается. Поток-производитель активен, он заполнит буфер информацией и перейдёт в состояние ожидания. Из этого состояния он сможет выйти только после того, как будет возобновлена (нажатием клавиши) работа потока-потребителя, который освободит место в буфере для помещения новой информации. В случае приостановки производителя возникнет аналогичная ситуация, только с пустым буфером. Приостановка/возобновление потока возможны в любом его состоянии – как в активном, так и в состоянии ожидания.

Задачи 2, 4, 5, 7 должны выполняться равномерно, независимо от степени загрузки системы. Для этого каждой из них необходимо получать управление через фиксированное количество “тиков” системного таймера, во время которого они выполнят какое-то свое элементарное действие (“бегущая строка” или “летающий объект” сместится на одну позицию, сменится нота в музыке…). При такой реализации скорость каждого потока будет определяться количеством “тиков” таймера между его запусками. Для уменьшения скорости такого потока достаточно после нажатия ключевой клавиши предоставлять ему управление реже, через большее число “тиков”, соответственно для ускорения такого потока – опять же после нажатия ключевой клавиши – ему предоставляется управление чаще, в пределе – на каждом “тике”. Так, “бегущая строка” должна двигаться равномерно с постоянной скоростью (если она не приостановлена ключевой клавишей) независимо от количества активных процессов в системе, музыка – тоже играть равномерно… Потоки этого класса задач могут иметь два статуса: “активен” и “приостановлен”.

Задания:

1. Два потока: первый читает информацию из файла (например, стихи или текст программы) в буфер, второй эту информацию из буфера выдаёт на экран. При заполнении окна вывода до конца его содержимое не должно обновляться полностью – вывод новой информации должен осуществляться в последнюю строку, а все остальные строки смещаться вверх (по материалам лаб. работы №4). Имя читаемого файла задавать как параметр командной строки. После окончания файла он начинает считываться заново.

3. Два потока: один выполняет поиск всех последовательных простых чисел и заносит их в буфер, второй осуществляет их вывод из буфера на экран (по материалам лаб. работы №4).

5. Вывод заголовка работы (фамилия и имя автора и название работы) в виде “бегущей строки” (по материалам лаб. работы №5). Место вывода (верхняя или нижняя строка экрана) задавать параметром командной строки.

8. В углу экрана с заданными в качестве параметров координатами поместить часы, показания которых должны соответствовать системному времени. Обновлять показания часов каждую секунду (по материалам лаб. работы №3).


Сведения об интерфейсе программы и детали его начальной реализации.

Реализация окон для процессов.

Ввиду того, что процессы, соответствующие заданиям 5, 8 не нуждаются в отдельных окнах (что вполне очевидно), то было принято решение распределить рабочую область экрана1 следующим образом:

  1.  бегущая строка, которая согласно заданию 5 выводится в верхней или нижней строке экрана, будет пробегать весь экран соответственно в первой или последней строке экрана. Для этого ей были выделены первая и последняя строки экрана.
  2.  часы, вообще говоря могут находится где угодно, но не стоит их помещать на окна активных процессов, так как получится перекрытие информации, выводимой одним процессом информацией, выводимой другим процессом и как результат – мигание «графических объектов». Поэтому часы лучше размещать в верхней или нижней строке экрана (но не в той же строке, где расположена бегущая строка).
  3.  процесс задания 1 состоит из двух потоков, для него выделено левое окно.
  4.  процесс задания 3 состоит из двух потоков, для него выделено правое окно.
  5.  в дополнительном, расположенном снизу, окне находится информация о клавишах управления процессами (потоками).

В итоге получаем такую «картину»:

О состояниях процессов (потоков) и способах их изменения.

Учитывая тот факт, что согласно заданиям 5, 8 процессы могут находиться только в двух состояниях («Активен» / «Приостановлен») было принято решение не отображать состояние этих процессов в виде информационного сообщения, так как и так ясно, что если процесс активен, то происходят соответствующие действия (движется бегущая строка, идут часы). Если один из этих процессов приостановлен, то вполне очевидно, что действие, выполняемое этим процессом, будет «заморожено». Таким образом, можно вполне конкретно определить состояние этих процессов в любой момент времени.

Что касается заданий 1, 3, то в них каждый из двух потоков может иметь три состояния («Активен» / «Ожидает» / «Приостановлен») [разумеется, только одно из трёх состояний в один промежуток времени]. Текущие состояния этих потоков отображаются после заголовка процесса.

Параметры командной строки.

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

work.exe 1 1 b text.txt

запускает программу с бегущей строкой внизу, часами в левом верхнем углу  и текст берётся из файла text.txt. В случае указания неправильных параметров программа выведет соответствующее сообщение и опишет формат ввода параметров.

Описание основных алгоритмов, используемых в программе.

Для поиска простых чисел используется следующий алгоритм. Берем число из переменной CurPrimeNumber (изначально там записана единица) и прибавляем к нему единицу до тех пор, пока оно не станет простым. Для проверки на простоту числа используется отдельная булева функция PrimeNumber. Найденное число заносится в буфер. Проверка на наличие свободного места в буфере находится в начале процедуры, поэтому, если в буфере нет свободного места, то поток переходит в состояние ожидания и новых простых чисел не ищет. Любое простое число, помещенное в буфер, не превосходит константы Infinity (равной MaxLongint). Поиск простых чисел продолжается до тех пор, пока не истечет время, отведенное на работу данного потока. Поток печати простых чисел проверяет буфер на пустоту и, если буфер не пуст, то извлекает первое число из буфера и выводит его на экран. Если буфер пуст, то поток переходит в режим ожидания. Буфер является FIFO структурой. Печать простых чисел происходит до истечения времени, отведенного этому потоку. Каждый из двух вышеописанных потоков могут получать дополнительное время, которое устанавливает пользователь путём нажатия соответствующих клавиш. После каждого добавления (и извлечения) элементов в буфер происходит обновление процента заполненности буфера. Потоки из задания 1 работают аналогично, только буфер используется строковый.

Бегущая строка движется справа налево. Скорость движения определяется переменной CLSpeed (изначально равной 4). Пользователь может изменять скорость движения бегущей строки путём нажатия соответствующих клавиш.

Часы при своём запуске получают системное время и далее начинают собственный отсчет с коррекцией. Показания часов на экране обновляются каждую секунду.

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

Положение часов.

«Строковая длина» часов – 8 символов («чч:мм:сс» – 8 символов). Поэтому часы можно поместить:

  1.  в верхний левый угол, задав в качестве координат (1, 1).
  2.  в нижний левый угол, задав в качестве координат (1, 25).
  3.  в верхний правый угол, задав в качестве координат (73, 1).
  4.  в нижний правый угол, задав в качестве координат (73, 25).

Таким образом, согласно условию, допустимы следующие способы вызова программы2:

work.exe 1 1 b text.txt

work.exe 1 25 a text.txt

work.exe 73 1 b text.txt

work.exe 73 25 a text.txt

Описание основных переменных, констант и типов.

В программе для фиксирования состояний (статусов) процессов и потоков определён следующий тип:

type Status = (Assigned, Wait, Suspended);

Также в программе имеются пять констант:

MaxBufferSize, _MaxBufferSize – размеры буферов;

Infinity – бесконечность (равная MaxLongint);

Line – текст бегущей строки.

__Delay – задержка для замедления работы потоков.

Глобальные переменные.

Buffer – буфер (реализован в виде массива), в который будут записываться простые числа;

_Buffer – буфер (реализован в виде массива), в который будут записываться строки из файла;

top, _top – вершины буферов;

StClock, StPNS, StPNP, StCL, StReader, StWriter – состояния процессов (потоков). Имеют описанный выше тип Status;

SaveInt8, _SaveInt8, SaveInt9 – процедуры (имеют тип Procedure) используемые при обработке прерываний таймера и клавиатуры;

PN_CTime, M_Ctime, C_Ctime, _cnt – счетчики времени, используемые соответствующими процессами (потоками) при их выполнении;

X_Clock, Y_Clock – координаты часов;

discr – частота обновления показаний таймера на экране для часов;

CorrectSecond – счетчик корректирующей секунды для часов;

Hour, Minute, Second – текущее время, которое показывают часов (в случае, когда часы были остановлены, оно, однако, не такое уж и текущее );

RunSeccчетчик прерываний с момента запуска часов;

time – время, выделенное потоку на выполнение;

CurPrimeNumber – текущее (и последнее найденное) простое число;

CLPos – позиция (текущая) бегущей строки;

CX, CY – координаты свободного места на экране при печати простых чисел;

CLSpeed – скорость движения бегущей строки;

StartPos, CurPos, LL – начальная и конечная позиция бегущей строки и её длина;

temp_str – временная переменная, используется для бегущей строки;

ScrM – массив для прямого доступа к видеопамяти;

_Close – флаг, указывающий на то, что нужно завершить работу программы;

PNS_Extra_Time, PNP_Extra_Time, RET, WET – дополнительное время для потоков.

F – переменная типа Text для считывания текста из файла.

Программная реализация.

Программа написана на Borland Pascal 7.

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

Вывод информации на экран.

При написании программы выяснилось, что имеющиеся в Borland Pascal функции вывода (Write[Ln]) не подходят, т. к. в том случае, когда несколько процессов выводят информацию на экран может случиться запись данных одного потока в окно другого потока ввиду того, что вызов процедур Write, WriteLn меняет положение курсора и, при одновременном «письме» нескольких потоков может получиться «смешивание» выводимых данных.

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

procedure WriteLine(const __Str: String; const __X, __Y: Integer);

type

 __Video = Array[1..25, 1..80] of Record

   symbol: Char;

   attr: Byte;

 end;

var

 __CurPos: Integer;

 __ScrM: __Video Absolute $B800:$0000;

begin

 __CurPos := __X;

 while (__CurPos <= 80) and (__CurPos - __X + 1 <= Length(__Str)) do

 begin

   __ScrM[__Y, __CurPos].attr := White;

   __ScrM[__Y, __CurPos].symbol := __Str[__CurPos - __X + 1];

   Inc(__CurPos);

 end;

end;

Для обработки прерываний клавиатуры используется процедура IntProcKeyboard, для обработки прерываний таймера – IntProc.

Сдвиг бегущей строки обеспечивает процедура ScreepingLine. Процедура TimeRefresh получает системное время и начинает собственный отсчет с корректировкой времени. Для поиска проверки числа на простоту используется булева функция PrimeNumber. Потоки поиска и печати простых чисел реализованы в виде процедур PrimeNumberSearch и PrimeNumberPrint. Инициализация переменных, используемых процессами и потоками реализована процедурой Initialize.

Описание остальных процедур вы можете посмотреть в приведённом исходном коде программы.

Скриншоты в различных ситуациях.

Неверное задание параметров командной строки.

«Нормальный» запуск программы.


Исходный код программы.

program work;

{$M $1000, 0, 0}

{$R+ $I+ $S+}

uses

 Crt, Dos;

type

 Status = (Assigned, Wait, Suspended); { Состояние процесса (потока) }

const

 MaxBufferSize = 15; { Размер буфера }

 _MaxBufferSize = 15;

 Infinity = MaxLongint; { Бесконечность }

 Line: String[30] = 'Бегущая строка...'; { Текст бегущей строки }

 __Delay = 15000;

var

 Buffer: Array[1..MaxBufferSize] of Longint; { Буфер }

 _Buffer: Array[1.._MaxBufferSize] of String[35];

 top, _top: Integer; { индекс последнего элемента и текущий размер буфера }

 StReader, StWriter, StClock, StPNS, StPNP, StCL: Status; { Состояния процессов (потоков) }

 SaveInt8, SaveInt9: Procedure; { Для обработки прерываний }

 RW_CTime, PN_CTime, M_Ctime, C_Ctime, cnt, cnt_d, _cnt: Word; { Для отсчета времени таймера }

 time: Word;                      { Время, выделенное потоку }

 CurPrimeNumber: Longint;         { Текущее (и последнее) простое число }

 X_Clock, Y_Clock: Integer;       { Координаты часов }

 discr: Integer;          { Частота обновления показаний таймера на экране }

 CorrectSecond: Byte;           { Счетчик корретирующей секунды }

 Hour, Minute, Second: Byte;    { Время (текущее), которое показывают часы }

 RunSec: Byte;                  { Счетчик прерываний с момента запуска }

 CLPos: Word;                   { Позиция (текущая) бегущей строки }

 CX, CY, WY: Byte;    { Координаты свободного места на экране при печати простых чисел }

 CLSpeed: Byte;    { Скорость движения бегущей строки }

 StartPos, CurPos, LL: Integer; { Начальная, конечная позиция бегущей строки и длина строки }

 temp_str: String[30];

 ScrM: Array[1..25, 1..80] of Record { для прямого доступа к видеопамяти }

   symbol: Char;

   attr: Byte;

 end Absolute $B800:$0000;

 RET, WET, PNS_Extra_Time, PNP_Extra_Time: Integer; { Дополнительное время для потоков, добавленное пользователем }

 F: Text;

 _Close: Boolean;

{ Вывод строки __Str на экран начиная с положения заданного

 координатами (__X; __Y). Использует прямой доступ к видеопамяти  }

procedure WriteLine(const __Str: String; const __X, __Y: Integer);

var

 __CurPos: Integer;

 __ScrM: Array[1..25, 1..80] of Record

   symbol: Char;

   attr: Byte;

 end Absolute $B800:$0000;

begin

 __CurPos := __X;

 while (__CurPos <= 80) and (__CurPos - __X + 1 <= Length(__Str)) do begin

   __ScrM[__Y, __CurPos].attr := White;

   __ScrM[__Y, __CurPos].symbol := __Str[__CurPos - __X + 1];

   Inc(__CurPos);

 end;

end;

{ Обновление показаний заполненности буфера }

procedure ProgressRefresh(const __MaxBufSize, __top, __Pos: Integer);

var

 S: String;

 V: Real;

begin

 V := __top / __MaxBufSize * 100;

 Str(V:2:2, S);

 WriteLine('Заполняемость буфера:', __Pos, 5);

 WriteLine(S + ' % ', __Pos + 22, 5);

end;

{ Возвращает True, если x - простое число }

function PrimeNumber(const x: Longint): Boolean;

var

 i: Integer;

begin

 PrimeNumber := False;

 if x <= 1 then Exit;

 for i := 2 to Trunc(Sqrt(x)) do

   if x mod i = 0 then Exit;

 PrimeNumber := True;

end;

{ Поиск простых чисел и занасение их в буфер }

procedure PrimeNumberSearch;

var

 S, ThreadTime: String;

begin

 case StPNS of { Выводим на экран состояние потока }

   Assigned:  WriteLine('Активен    ', 51, 3);

   Wait:      WriteLine('Ожидание   ', 51, 3);

   Suspended: WriteLine('Остановлен ', 51, 3);

 end;

 if (StPNS = Suspended) or (top >= MaxBufferSize) then begin

   PN_CTime := High(PN_CTime);

   if top >= MaxBufferSize then begin { Буфер полон }

     StPNS := Wait;       { Переходим в режим ожидания }

     WriteLine('Ожидание   ', 51, 3); { Обновляем состояние на экране }

   end;

   Exit;

 end;

 if StPNS = Wait then begin { Переходим в активный режим, если ждали }

   StPNS := Assigned;

   WriteLine('Активен    ', 51, 3); { Обновляем состояние на экране }

 end;

 repeat  { ищем следующее за CurPrimeNumber простое число }

   Inc(CurPrimeNumber);

 until PrimeNumber(CurPrimeNumber) or (CurPrimeNumber >= Infinity);

 { Если найденное число не простое, то это значит, что следующее

   простое число не помещается в тип Longint. Выходим             }

 if not PrimeNumber(CurPrimeNumber) then Exit;

 { Добавляем число в буфер в позицию top }

 Inc(top);

 Buffer[top] := CurPrimeNumber;

 ProgressRefresh(MaxBufferSize, top, 41); { Обновляем показания нашего ProgressBar'а }

 Delay(__Delay);  { Заданная задержка }

end;

{ Вывод на экран простых чисел из буфера }

procedure PrimeNumberPrint;

var

 i: Integer;

 X, Y: Integer;

 tmp, S: String;

begin

 case StPNP of  { Выводим на экран состояние потока }

   Assigned:  WriteLine('Активен    ', 51, 4);

   Wait:      WriteLine('Ожидание   ', 51, 4);

   Suspended: WriteLine('Остановлен ', 51, 4);

 end;

 if (StPNP = Suspended) or (top <= 0) then begin

   PN_CTime := High(PN_CTime);

   if top <= 0 then begin

     StPNP := Wait;

     WriteLine('Ожидание   ', 51, 4);

   end;

   Exit;

 end;

 if StPNP = Wait then begin { Переходим в активный режим, если ждали }

   WriteLine('Активен    ', 51, 4);

   StPNP := Assigned;

 end;

 Str(Buffer[1], tmp);

 { Если число не помещается в текущей строке - переходим на следующую }

 if CX + Length(tmp) + 1 > 34 then begin

   CX := 1; { И пишем с начала строки }

   Inc(CY);

 end;

 { Если следующей строки нет - очищаем область окна и пишем по новому }

 if CY > 13 then begin

   CY := 9;

   Window(41, 5, 78, 16);

   TextBackGround(Black);

   ClrScr;

 end;

 WriteLine(tmp + ' ', 40 + CX, CY); { Собственно пишем }

 CX := CX + Length(tmp) + 1; { Фиксируем текущую свободную позицию }

 { Удаляем первое число из буфера. Это FIFO структура. Можно

   было реализовать лучше, не используюя сдвиг элементов массива,

   но здесь это особой роли не играет }

 Dec(top);

 for i := 1 to top do

   Buffer[i] := Buffer[i + 1];

 ProgressRefresh(MaxBufferSize, top, 41); { Обновляем показания нашего ProgressBar'а }

 Delay(__Delay);

end;

{ Сдвигает бегущую строку }

procedure CreepingLine;

begin

 if StartPos > 1 then

   Dec(StartPos)

 else

   StartPos := 80;

 CurPos := StartPos;

 temp_str := ScrM[CLPos, CurPos].symbol + temp_str;

 while (CurPos <= 80) and (CurPos - StartPos <= LL) do begin

   ScrM[CLPos, CurPos].attr := LightRed;

   ScrM[CLPos, CurPos].symbol := Line[CurPos - StartPos + 1];

   Inc(CurPos);

 end;

 if StartPos + LL <= 80 then begin

   ScrM[CLPos, StartPos + LL].attr := LightGray;

   ScrM[CLPos, StartPos + LL].symbol := temp_str[Length(temp_str)];

   Delete(temp_str, Length(temp_str), 1);

 end;

 if (StartPos >= 81 - LL) and (ScrM[CLPos, 1].attr = LightRed) then begin

   CurPos := 1;

   while CurPos <= LL - (80 - StartPos + 1) do begin

     ScrM[CLPos, CurPos].attr := LightRed;

     ScrM[CLPos, CurPos].symbol := Line[80 - StartPos + 1 + CurPos];

     Inc(CurPos);

   end;

   ScrM[CLPos,LL-(80-StartPos+1)+1].attr := LightGray;

   ScrM[CLPos,LL-(80-StartPos+1)+1].symbol := temp_str[length(temp_str)];

   Delete(temp_str,length(temp_str),1);

 end;

end;

{ Добавляет нули слева (при необходимости) для времени }

function LeadingZero(const W: Word): String;

var

 S: String;

begin

 Str(W:0, S);

 if Length(S) = 1 then S := '0' + S;

 LeadingZero := S;

end;

{ переводит время в "человеческий" формат }

procedure CheckTime;

begin

 if Second = 60 then

 begin

   Second := 0;

   Inc(Minute);

   if Minute = 60 then

   begin

     Minute := 0;

     Inc(Hour);

     if Hour = 24 then

       Hour := 0;

   end;

 end;

end;

{ Получает системное время и начинает собственный отсчет с помощью прерываний

 таймера                                                                      }

procedure TimeRefresh;

var

 CH, CM, CS, CS100: Word;

begin

 RunSec := 0;

 GetTime(CH, CM, CS, CS100);

 discr := 1;

 cnt_d := discr;

 Hour := CH;

 Minute := CM;

 Second := CS;

 CorrectSecond := 5;

 cnt := Trunc((99 - CS100) * 0.18);

end;

{ Процедура обработки прерываний системного таймера }

{$F+}

procedure IntProc;

Interrupt;

begin

 Inc(PN_CTime);

 Inc(RW_CTime);

 if StClock <> Suspended then { Если процесс "Часы" не остановлен }

 begin

   if cnt = 0 then

   begin

     Inc(Second);

     CheckTime;

     Inc(RunSec);

     Inc(cnt_d);

     Dec(CorrectSecond);

     if CorrectSecond = 0 then

     begin

       CorrectSecond:=5;

       cnt := 19;

     end

     else

       cnt := 18;

     if cnt_d >= discr then

     begin

       cnt_d := 0;

       WriteLine(LeadingZero(Hour) + ':' + LeadingZero(Minute) +

         ':' + LeadingZero(Second), X_Clock, Y_Clock);

     end;

     if RunSec mod 20 = 0 then

     begin

       Inc(Second);

       CheckTime;

       if (20 mod discr = 0) or (discr mod 20 = 0) then

         WriteLine(LeadingZero(Hour) + ':' + LeadingZero(Minute) +

           ':' + LeadingZero(Second), X_Clock, Y_Clock);

     end;

     if RunSec = 100 then

     begin

       RunSec := 0;

       Inc(Second);

       CheckTime;

       if (20 mod discr = 0) or (discr mod 20 = 0) then

         WriteLine(LeadingZero(Hour) + ':' + LeadingZero(Minute) +

           ':' + LeadingZero(Second), X_Clock, Y_Clock);

     end;

   end

   else

     Dec(cnt);

 end;

 if StCL <> Suspended then begin { Если процесс "Бегущая строка" не остановлен }

   Inc(_cnt);

   if _cnt > round(18.2 / CLSpeed) then begin

     _cnt := 0;

     CreepingLine;

   end;

 end;

 Inline($9C);

 SaveInt8;

end;

{$F-}

{ Поток чтения из файла }

procedure Reader;

var

 S: String[37];

 c: Char;

 i: Integer;

begin

 case StReader of { Выводим на экран состояние потока }

   Assigned:  WriteLine('Активен    ', 12, 3);

   Wait:      WriteLine('Ожидание   ', 12, 3);

   Suspended: WriteLine('Остановлен ', 12, 3);

 end;

 if (StReader = Suspended) or (_top >= _MaxBufferSize) then begin

   RW_CTime := High(RW_CTime);

   if _top >= _MaxBufferSize then begin { Буфер полон }

     StReader := Wait;       { Переходим в режим ожидания }

     WriteLine('Ожидание   ', 12, 3); { Обновляем состояние на экране }

   end;

   Exit;

 end;

 if StReader = Wait then begin{ Переходим в активный режим, если ждали }

   StReader := Assigned;

   WriteLine('Активен    ', 12, 3); { Обновляем состояние на экране }

 end;

 S := '';

 i := 1;

 while not EOF(F) and (i <= 35) do begin { Читаем 35 символов из файла }

   Read(F, c);

   if (c = #13) then Break;

   if (c = #10) then Continue;

   S := S + c;

   Inc(i);

 end;

 if EOF(F) then Reset(F);  { Если дошли до конца файла - открываем заново }

 Inc(_top);

 _Buffer[_top] := S;

 ProgressRefresh(_MaxBufferSize, _top, 3);

 Delay(__Delay);  { Заданная задержка }

end;

{ Поток вывода прочитанных из файла данных }

procedure Writer;

var

 i, j: Integer;

begin

 case StWriter of  { Выводим на экран состояние потока }

   Assigned:  WriteLine('Активен    ', 12, 4);

   Wait:      WriteLine('Ожидание   ', 12, 4);

   Suspended: WriteLine('Остановлен ', 12, 4);

 end;

 if (StWriter = Suspended) or (_top <= 0) then begin

   RW_CTime := High(RW_CTime);

   if _top <= 0 then begin

     StWriter := Wait;

     WriteLine('Ожидание   ', 12, 4);

   end;

   Exit;

 end;

 if StWriter = Wait then begin { Переходим в активный режим, если ждали }

   WriteLine('Активен    ', 12, 4);

   StWriter := Assigned;

 end;

 { Если следующей строки нет }

 if WY > 16 then begin

   WY := 16;

   for i := 7 to 15 do

     for j := 3 to 37 do begin

       ScrM[i, j].Attr := ScrM[i + 1, j].Attr;

       ScrM[i, j].Symbol := ScrM[i + 1, j].Symbol;

     end;

 end;

 while Length(_Buffer[1]) <> 35 do

   _Buffer[1] := _Buffer[1] + ' ';

 WriteLine(_Buffer[1], 3, WY); { Собственно пишем }

 Inc(WY);

 { Удаляем первое число из буфера. Это FIFO структура. Можно

   было реализовать лучше, не используюя сдвиг элементов массива,

   но здесь это особой роли не играет }

 Dec(_top);

 for i := 1 to _top do

   _Buffer[i] := _Buffer[i + 1];

 ProgressRefresh(_MaxBufferSize, _top, 3);

 Delay(__Delay);

 if RW_CTime > time + WET then

   WriteLine('Время вышло    ', 12, 4);

end;

{ Инициализация переменных перед запуском основных процедур }

procedure Initialize;

begin

 StClock := Assigned;

 StPNS := Assigned;

 StPNP := Wait;

 StCL := Assigned;

 StReader := Assigned;

 StWriter := Wait;

 M_CTime := 0;

 CLSpeed := 12;

 LL := Length(Line);

 _cnt := 0;

 StartPos := 81;

 top := 0;

 _top := 0;

 CurPrimeNumber := 1;

 CX := 1;

 CY := 7;

 WY := 7;

 PNS_Extra_Time := 0;

 PNP_Extra_Time := 0;

 RET := 0;

 WET := 0;

 _Close := False;

 TimeRefresh;

end;

{ Процедура завершения работы программы }

procedure TheEnd;

begin

 SetIntVec($8, Addr(SaveInt8));

 SetIntVec($9, Addr(SaveInt9));

 StPNS := Suspended;

 StReader := Suspended;

 time := 0;

 PNS_Extra_Time := 0;

 RET := 0;

 StPNP := Assigned;

 StWriter := Assigned;

 Randomize;

 { Считываем всё оставшееся из буферов }

 while (top > 0) or (_top > 0) do begin

   case Random(2) of

     0: if  top > 0 then PrimeNumberPrint;

     1: if _top > 0 then Writer;

   end;

 end;

 StPNP := Suspended;

 StClock := Suspended;

 StCL := Suspended;

 Window(1, 1, 80, 25);

 GotoXY(1, 24);

 NoSound;

 Halt(0);

end;

{ Процедура обработки прерываний клавиатуры }

{$F+}

procedure IntProcKeyboard;

Interrupt;

begin

 case Port[$60] of

   1:  _Close := True; { нажата Esc }

   2:  if PNS_Extra_Time > 0 then Dec(PNS_Extra_Time);   { нажата 1 }

   3:  if PNS_Extra_Time < 10 then Inc(PNS_Extra_Time);  { нажата 2 }

   4:  if PNP_Extra_Time > 0 then Dec(PNP_Extra_Time);   { нажата 3 }

   5:  if PNP_Extra_Time < 10 then Inc(PNP_Extra_Time);  { нажата 4 }

   6:  if RET > 0 then Dec(RET);                         { нажата 6 }

   7:  if RET < 10 then Inc(RET);                        { нажата 7 }

   8:  if WET > 0 then Dec(WET);                         { нажата 8 }

   9:  if WET < 10 then Inc(WET);                        { нажата 9 }

   51: if CLSpeed < 16 then Inc(CLSpeed);       { нажата < }

   52: if CLSpeed > 1 then Dec(CLSpeed);        { нажата > }

   59:   { нажата F1 }

     if StClock = Assigned then

       StClock := Suspended

     else

     begin

       TimeRefresh;

       StClock := Assigned;

     end;

   60: if StCL = Assigned then StCL := Suspended else StCL := Assigned;           { нажата F2 }

   61: if StPNS <> Suspended then StPNS := Suspended else StPNS := Assigned;      { нажата F3 }

   62: if StPNP <> Suspended then StPNP := Suspended else StPNP := Assigned;      { нажата F4 }

   63: if StReader <> Suspended then StReader := Suspended else StReader := Assigned;      { нажата F5 }

   64: if StWriter <> Suspended then StWriter := Suspended else StWriter := Assigned;      { нажата F6 }

 end;

 Inline($9C);

 SaveInt9;

end;

var

 Code1, Code2, N: Integer;

 _CLPos: String;

begin

 Val(ParamStr(1), X_Clock, Code1);

 Val(ParamStr(2), Y_Clock, Code2);

 _CLPos := ParamStr(3);

 Assign(F, ParamStr(4));

 {$I-}

 Reset(F);

 {$I+}

 if (Code1 <> 0) or (Code2 <> 0) or (X_Clock < 0) or (X_Clock > 73) or

    (Y_Clock < 0) or (Y_Clock > 25) or (ParamCount <> 4) or ((Upcase(_CLPos[1]) <> 'A') and (Upcase(_CLPos[1]) <> 'B')) then

 begin

   WriteLn;

   WriteLn('Неверные параметры.');

   WriteLn;

   WriteLn('Правильный формат:');

   WriteLn(' имя_файла X Y P File_Name');

   WriteLn('X, Y - координаты часов');

   WriteLn('P - символ - положение бегущей строки:');

   WriteLn('a - вверху экрана, b - внизу.');

   WriteLn('File_Name - имя файла с текстом (в Dos кодировке)');

   Halt;

 end;

 if IOResult <> 0 then begin

   WriteLn('Не удаётся открыть файл: ', ParamStr(2));

   Halt;

 end;

 if Upcase(_CLPos[1]) = 'A' then CLPos := 1 else CLPos := 25;

 { Заполняем экран начальными данными и окнами }

 TextBackGround(Black);

 ClrScr;

 Window(2, 2, 38, 17);

 TextBackGround(1);

 ClrScr;

 TextColor(White);

 GotoXY(3, 1);

 Write('Процесс работы с текстом из файла');

 Window(3, 3, 37, 16);

 TextBackGround(Black);

 ClrScr;

 Window(40, 2, 79, 17);

 TextBackGround(2);

 ClrScr;

 TextColor(White);

 GotoXY(4, 1);

 Write('Процесс работы с простыми числами');

 Window(41, 3, 78, 16);

 TextBackGround(Black);

 ClrScr;

 WriteLine('Поток 1:', 3, 3);

 WriteLine('Поток 2:', 3, 4);

 WriteLine('Поток 1:', 41, 3);

 WriteLine('Поток 2:', 41, 4);

 Window(1, 18, 80, 24);

 TextBackGround(3);

 ClrScr;

 WriteLn('Esc - выход, F1 - запустить/остановить часы, F2 - аналогично для бег. стр., ');

 WriteLn('F3 - изменить состояние ("Активен"/"Остановлен") потока поиска простых чисел,');

 WriteLn('F4 - изменить состояние ("Активен"/"Остановлен") потока печати простых чисел,');

 WriteLn('F5, F6 - аналогично для потоков чтения из файла и вывода текста.');

 WriteLn('1/2 - увеличить/уменьшить время работы потока поиска простых числел,');

 WriteLn('3/4 - аналогично для печати печати простых чисел, 5/6, 7/8 - аналогично для');

 Write('чтения/печати текста, </> - увелич./уменьш. скорости бегущей. строки');

 Initialize;

 Randomize;

 GetIntVec($8, @SaveInt8);

 SetIntVec($8, Addr(IntProc));

 GetIntVec($9, @SaveInt9);

 SetIntVec($9, Addr(IntProcKeyboard));

 while True do begin

   if _Close then TheEnd;

   time := Random(3) + 1;

   PN_CTime := 0;

   RW_CTime := 0;

   case Random(4) of

     0:

     begin

       while PN_CTime < time + PNS_Extra_Time do PrimeNumberSearch;

       if StPNS = Assigned then WriteLine('Время вышло   ', 51, 3);

     end;

     1:

     begin

       while PN_CTime < time + PNP_Extra_Time do PrimeNumberPrint;

       if StPNP = Assigned then WriteLine('Время вышло   ', 51, 4);

     end;

     2:

     begin

       while RW_CTime < time + RET do Reader;

       if StReader = Assigned then WriteLine('Время вышло    ', 12, 3);

     end;

     3:

     begin

       while RW_CTime < time + WET do Writer;

       if StWriter = Assigned then WriteLine('Время вышло    ', 12, 4);

     end;

   end;

 end;

end.

1 консольного окна, в случае запуска программы под управлением ОС Windows.

2 Имеется ввиду, что экран состоит из 25 строк и по 80 символов в каждой строке.

PAGE   \* MERGEFORMAT 1




1. Развитие критического мышления учащихся в процессе обучения географии.html
2. а Там складывается цена ресурсов труда определяются условия ее найма в том числе величина заработной платы
3. Этика
4. Биография НА Бердяева
5. тема заповедников формировалась в течение 80 лет и насчитывает в настоящее время 100 заповедников общей.html
6. стоматолог- Макарова В.
7. м году ездили мы с Васей
8. семибоярщина Новая династия Романовы
9. Реферат- Особенности ведения уголовных дел
10. Эволюция концепции маркетинга.html
11. Реферат Шульгиной Анны Михайловны Лебедевой Екатерины Александровны Группа 1МI СанктПе
12. Роль Наполеона в вопросах внешней и внутренней политики
13. Incentives r~unions ou voyges de stimultion s~minires et r~unions d~entreprises
14. Методические рекомендации по раскрытию хищений с применением подложных кредитовых авизо В 199192 годах на
15. bout Cnd
16.  Роббинс Л. Логика выбора
17. Измерительный контроль в оптической микроскопии.html
18. Лекция четвертая СОЦИОЛОГИЯ КАРЛА МАРКСА Содержание Штрихи к портрету Марксизм марксизмы и социологи
19. тематики 1 класс УМК Школа 2100 Тема
20. тема видов деятельности как условие разностороннего развития личности