3122

Реализация параллельной работы нескольких процессов программным методом

Курсовая

Информатика, кибернетика и программирование

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

Русский

2014-06-10

258 KB

25 чел.

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

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

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

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

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

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

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

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

Задания:

2. Музыкальное сопровождение – как минимум несколько нот различной длительности, образующие мелодию. Во включённом состоянии мелодия должна играть в фоновом режиме (по материалам лаб. работы №2).

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

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

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


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

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

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

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

В итоге получаем такую «картину» (см. следующую страницу):

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

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

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

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

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

solution.exe 1 1 b

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

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

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

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

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

solution.exe 1 1 b

solution.exe 1 25 a

solution.exe 73 1 b

solution.exe 73 25 a

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

Музыкальное сопровождение реализовано как фоновый процесс. Случайным образом выбирается новая частота звука, когда прошло определенное число «тиков» таймера. Это число определяется переменной M_Refresh.

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

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

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

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

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

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

type Status = (Assigned, Wait, Suspended);

Также в программе имеются три константы (одна из которых – именованная):  MaxBufferSize – размер буфера; Infinity – бесконечность (равная MaxLongint) и Line – текст бегущей строки.

Глобальных переменных в программе 40:

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

top – индекс последнего добавленного числа в буфер. Также это и текущий размер (количество элементов) буфера;

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

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

t_delay – задержка для просмотра программы в замедленном режиме;

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

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

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

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

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

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

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

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

M_Refresh – время, через которое сменяется нота музыки;

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

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

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

fl_next – флаг перемещения строки;

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

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

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

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

PNS_Extra_Time, PNP_Extra_Time – дополнительное время для потоков поиска и печати простых чисел, добавляемое пользователем.

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

Программа написана на 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 и _IntProc.

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

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

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

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

Отсутствие параметров командной строки.

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

Завершение программы при нажатии Esc.


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

program solution;

{$M $1000, 0, 0}

uses

 Crt, Dos;

type

 Status = (Assigned, Wait, Suspended);

const

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

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

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

var

 Buffer: Array[1..MaxBufferSize] of Longint;

 top: Integer;

 StMusic, StPNS, StPNP, StCL, StClock: Status;

 SaveInt8, _SaveInt8, SaveInt9: Procedure;

 T_Delay: Integer;                        

 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;                           

 M_Refresh: Integer;                     

 CLPos: Word;                            

 CX, CY: Byte;    

 CLSpeed: Byte;   

 fl_next: Boolean;

 StartPos, CurPos, LL: Integer;

 temp_str: String[30];

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

   symbol: Char;

   attr: Byte;

 end Absolute $B800:$0000;

 _TheEnd: Boolean;  

 PNS_Extra_Time, PNP_Extra_Time: Integer;

{ Вывод строки __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;

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

 простых чисел }

{$F+}

procedure _IntProc;

Interrupt;

begin

 Inc(PN_CTime);

 Inline($9C);

 _SaveInt8;

end;

{$F-}

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

procedure ProgressBarRefresh;

var

 BufferProgressBar: String[35];

begin

 BufferProgressBar := '';

 while Length(BufferProgressBar) < 35 * top div MaxBufferSize do

   BufferProgressBar := BufferProgressBar + Chr(219);

 while Length(BufferProgressBar) < 35 do

   BufferProgressBar := BufferProgressBar + Chr(176);

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

 WriteLine(BufferProgressBar, 3, 10);

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('Активен    ', 3, 4);

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

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

 end;

 if (StPNS = Suspended) or ((StPNS = Wait) and (top >= MaxBufferSize)) then Exit;

 GetIntVec($8, @_SaveInt8);

 SetIntVec($8, Addr(_IntProc));

 PN_CTime := 0;                  { Текущее местное время для потока }

 while PN_CTime < time + PNS_Extra_Time do { пока не исчерпано стандартное и дополнительное время этого потока }

 begin

   Str(time, S);

   WriteLine('Выделенное время: ' + S + '       ', 3, 6);

   Str(PNS_Extra_Time, S);

   WriteLine('Дополнительное время: ' + S + '      ', 3, 7);

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

   begin

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

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

     Break;

   end

   else

   begin

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

     begin

       StPNS := Assigned;

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

     end;

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

       Inc(CurPrimeNumber);

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

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

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

     if not PrimeNumber(CurPrimeNumber) then Exit;

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

     Inc(top);

     Buffer[top] := CurPrimeNumber;

     ProgressBarRefresh; { Обновляем показания нашего ProgressBar'а }

   end;

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

 end;

 { Сообщаем, что поток отработал свое время }

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

 SetIntVec($8, Addr(_SaveInt8));

end;

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

procedure PrimeNumberPrint;

var

 i: Integer;

 X, Y: Integer;

 tmp, S: String;

begin

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

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

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

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

 end;

 if (StPNP = Suspended) or ((StPNP = Wait) and (top <= 0)) then Exit;

 GetIntVec($8, @_SaveInt8);

 SetIntVec($8, Addr(_IntProc));

 PN_CTime := 0;                  { Текущее местное время для потока }

 while PN_CTime < time + PNP_Extra_Time do  { пока не исчерпано стандартное и дополнительное время этого потока }

 begin

   Str(time, S);

   WriteLine('Выделенное время: ' + S + '       ', 41, 6);

   Str(PNP_Extra_Time, S);

   WriteLine('Дополнительное время: ' + S + '      ', 41, 7);

   if top > 0 then { Если буфер не пуст }

   begin

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

     begin

       WriteLine('Активен    ', 41, 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];

     ProgressBarRefresh; { Обновляем показания нашего ProgressBar'а }

   end

   else  { Буфер пуст. Переходим в состояние ожидания }

   begin

     StPNP := Wait;

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

     Break;

   end;

   Delay(T_Delay);

 end;

 { Сообщаем, что процесс отработал свое время }

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

 SetIntVec($8, Addr(_SaveInt8));

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;

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

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;

{ Процедура обработки прерываний таймера для часов, музыки и бегущей строки }

{$F+}

procedure IntProc;

Interrupt;

begin

 if StMusic <> Suspended then { Если процесс "Музыка" не остановлен }

 begin

   Inc(M_CTime);

   if M_CTime = M_Refresh then

   begin

     M_CTime := 0;

     Randomize;

     NoSound;

     Sound(Random(6000));

   end;

 end;

 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 Initialize;

begin

 _TheEnd := False;

 StMusic := Assigned;

 StPNS := Assigned;

 StPNP := Wait;

 StCL := Assigned;

 StClock := Assigned;

 M_CTime := 0;

 M_Refresh := 2;

 CLSpeed := 12;

 LL := Length(Line);

 _cnt := 0;

 StartPos := 81;

 top := 0;

 CurPrimeNumber := 1;

 CX := 1;

 CY := 9;

 PNS_Extra_Time := 0;

 PNP_Extra_Time := 0;

 TimeRefresh;

end;

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

procedure TheEnd;

begin

 StPNS := Suspended; { Останавливаем поток поиска простых чисел }

 time := 0;

 PNS_Extra_Time := 0;

 StPNP := Assigned;

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

 begin

   time := 2;

   PrimeNumberPrint;

 end;

 StPNP := Suspended;

 StMusic := Suspended;

 StClock := Suspended;

 StCL := Suspended;

 Window(1, 1, 80, 25);

 TextBackGround(White);

 ClrScr;

 TextColor(LightRed);

 GotoXY(36, 12);

 WriteLn('HAPPY END');

 GotoXY(1, 24);

 NoSound;

 Halt(0);

end;

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

{$F+}

procedure IntProcKeyboard;

Interrupt;

begin

 case Port[$60] of

   1: { нажата Esc }

     begin

       PN_CTime := High(PN_CTime); { Время работы потоков. Принудительно завершаем поток. }

       _TheEnd := True; { Устанавливаем флаг выхода }

     end;

   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 }

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

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

   59: { нажата F1 }

     if StMusic = Assigned then

     begin

       NoSound;

       StMusic := Suspended;

     end

     else StMusic := Assigned;      

   60: { нажата F2 }

     if StClock = Assigned then

       StClock := Suspended

     else

     begin

       TimeRefresh;

       StClock := Assigned;

     end;

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

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

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

 end;

 Inline($9C);

 SaveInt9;

end;

var

 Code: Integer;

 _CLPos: String;

begin

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

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

 _CLPos := ParamStr(3);

 if ParamCount = 0 then

 begin

   WriteLn;

   WriteLn('Не были указаны параметры командной строки.');

   WriteLn('Программа будет запущена с параметрами по умолчанию');

   WriteLn;

   WriteLn('Для продолжения нажмите любую клавишу...');

   ReadKey;

   X_Clock := 73;

   Y_Clock := 1;

   _CLPos := 'B';

 end

 else if (ParamCount <> 3) or (X_Clock <= 0) or (X_Clock > 73) or

   (Y_Clock <= 0) or (Y_Clock > 25) or

     ((Upcase(_CLPos[1]) <> 'A') and (Upcase(_CLPos[1]) <> 'B')) then

 begin

   WriteLn;

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

   WriteLn;

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

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

   WriteLn('где X, Y - координаты положения часов,');

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

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

   Halt;

 end;

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

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

 TextBackGround(Black);

 ClrScr;

 Window(2, 2, 38, 17);

 TextBackGround(1);

 ClrScr;

 Window(3, 3, 37, 16);

 TextBackGround(Black);

 ClrScr;

 WriteLine('Поток 1. Поиск простых чисел.', 3, 3);

 Window(40, 2, 79, 17);

 TextBackGround(2);

 ClrScr;

 Window(41, 3, 78, 16);

 TextBackGround(Black);

 ClrScr;

 WriteLine('Поток 2. Печать найденных чисел.', 41, 3);

 Window(2, 19, 79, 24);

 TextBackGround(3);

 ClrScr;

 WriteLn('Esc - завершение работы программы, F1 - запустить/остановить музыку,');

 Write('F2 - запустить/остановить часы, ');

 WriteLn('F3 - запустить/остановить бегущую строку,');

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

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

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

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

 T_Delay := 9000;

 Initialize;

 Randomize;

 GetIntVec($8, @SaveInt8);

 SetIntVec($8, Addr(IntProc));

 GetIntVec($9, @SaveInt9);

 SetIntVec($9, Addr(IntProcKeyboard));

 while True do

 begin

   if _TheEnd then TheEnd;

   time := Random(2) + 1;

   case Random(2) + 1 of

     1: PrimeNumberSearch;

     2: PrimeNumberPrint;

   end;

 end;

end.


 

А также другие работы, которые могут Вас заинтересовать

49516. Расчет установки Сушилка Кипящий слой 199.5 KB
  Сушилка кипящего слоя Сушилка кипящего слоя используется для непрерывной и периодической сушки самых разных сыпучих материалов: от песка и химических реактивов до пластмассовой дроблёнки и древесных опилок. Для увеличения производительности сушилка может компоноваться из нескольких секций Сушилка кипящего слоя выгодно отличается от сушилок других типов экономичностью компактностью и надёжностью. Конструирование сушилок кипящего слоя. Сушильные установки кипящего слоя состоят из сушильной камеры газораспределительного...
49517. Проектирование участка внутризоновой единой сети связи Российской Федерации 561.49 KB
  В данном курсовом проекте будет произведено проектирование участка внутризоновой единой сети связи Российской Федерации. Структура проектируемой сети представляет собой кольцо SDH с центральной станцией – г. Новосибирск. Также на сети имеется участок PDH на многомодовом оптическом кабеле.
49518. Проектирование линейной автоматической системы управления 1.18 MB
  Анализ объекта управления Идентификация объекта управления получие параметров передаточной функции kоб Тоб tоб Построение амплитудно-частотной и фазовочастотной характеристики объекта Блоксхема автоматизированного проектирования Выводы Список использованной литературы Задание Цель работы: для заданного объекта регулирования требуется спроектировать АСР с заданным типом регулятора ПИрегулятор.
49519. Защита понижающего трансформатора 172 KB
  Основные защиты реагируют на все виды повреждений трансформатора и действуют на отключение выключателей со всех сторон без выдержки времени. Резервные защиты резервируют основные защиты и реагируют на внешние к. Резервные защиты от междуфазных повреждений имеют несколько вариантов исполнения: а МТЗ максимальная токовая защита без пуска по напряжению; б МТЗ с комбинированным пуском по напряжению; в МТЗ обратной последовательности с приставкой для действия при симметричных к. Резервные защиты...
49520. Эконометрика. ОҚУ-ӘДІСТЕМЕЛІК КЕШЕН 220.5 KB
  “Эконометрика” пәнінің бағдарламасы ҚР Білім және ғылым министрлігі бекіткен жоғары кәсіптік білім берудің Жалпыға міндетті білім беру стандартының дипломдандырылған мамандарды (бакалавр) дайындау деңгейіне және міндетті минимум мазмұны талаптарына
49521. Сушильный барабан для сушки шлака 234.5 KB
  Материал уложен на решетку продуваемую газом со скоростью необходимой для создания кипящего слоя Температура материала максимальная температура нагрева В зависимости от свойств высушиваемого материала. В зависимости от свойств высушиваемого материала. Расход тепла кДж кг 58008000 50006000 Расход электроэнергии кВтч т 57 1015 Напряжение по влаге m0 Кг влаги м3 ч 50150 150200 Время сушки материала 2040 мин 1020 секунд Область применения Сушка кусковых материалов Сушка зернистых и сыпучих некомкующихся материалов сведения взяты...
49522. Исследование рычажного механизма 4.37 MB
  Для этого из центра О делают засечку радиусом R = ВBС на траектории точки С которая представляет собой прямую линию вдоль которой движется ползун. Делим траекторию точки В на 12 равных частей и строим 12 положений механизма. Второе мертвое положение соответствует случаю когда шатун и кривошип перекрывают друг друга тогда из точки А делается засечка радиусом R=СBВ на траектории точки С. Траектория этой точки представлена пунктирной линией.