Механизм межзадачного взаимодействия с помощью семафоров

Автор: Пользователь скрыл имя, 17 Января 2011 в 21:52, лабораторная работа

Описание работы

Семафор – это защищенная переменная, значение которой можно опрашивать и изменять с помощью специальных операций. Двоичные семафоры принимают два значения («0» и «1»), считающие семафоры (семафоры со счетчиками) принимают целые неотрицательные значения.

Работа содержит 1 файл

Лабораторная работа готовая.doc

— 302.00 Кб (Скачать)

 
 
 

 
 
 
 
 
 
 
 

Лабораторная  работа №1

по  курсу:

Системы реального времени 

      «Механизм межзадачного взаимодействия с помощью семафоров» 
 
 
 
 
 
 
 
 

Выполнила ст. группы З-245

Черныш  Е.П.

Проверила Глод О.Д. 
 
 
 
 
 
 
 
 
 
 

Таганрог 2010

      Семафор –  это защищенная переменная, значение которой можно опрашивать и изменять с помощью специальных операций. Двоичные семафоры принимают два значения («0» и «1»), считающие семафоры (семафоры со счетчиками) принимают целые неотрицательные значения.

      Если  на время работы обрабатывающей программы с некоторым ресурсом доступ к нему со стороны других программ нужно запретить, то эта обрабатывающая программа перед обращением к ресурсу устанавливает соответствующий семафор в «0» и тем самым запрещает доступ к нему.  По окончанию работы с ресурсом программа возвращает значение семафора в «1», тем самым снимает запрет.

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

      До  происхождения события  семафор устанавливается в «0», и, когда процесс A в ходе своего выполнения доходит до той точки, когда дальнейшее его выполнения зависит от ожидаемого события, он блокируется.  Со временем процесс B обнаруживает наступление события и переводит семафор в состояние «1», сигнализируя, что событие произошло. Таким образом, первый процесс получает возможность возобновить свое выполнение, т.е. обработку произошедшего события.

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

     Над семафорами вводятся операции:

  • P(S) – операция открытия семафора S(эта операция уменьшает счётчик семафора на 1);
  • V(S) - операция закрытия семафора S(эта операция увеличивает счётчик семафора на 1).

Решение задачи «взаимоисключающий доступ»

с помощью механизма  семафоров

     Есть  два процесса (процесс A и процесс B), которые во время своего выполнения обращаются к разделяемому ресурсу. Требуется исключить одновременные обращения процессов к критическому ресурсу. При этом необходимо, чтобы задержка любого процесса вне его критической секции не влияла на работу другого процесса. Решение должно быть симметричным для обоих процессов (оба процесса равноправны). Оба процесса являются циклическими и имеют 2 этапа работы:

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

Описание  программы «взаимоисключающий доступ»

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

    Semaphore := CreateSemaphore(nil, 1,1,'NameSemaphore');

со следующими  параметрами: начальное значение счётчика = 1, максимальное значение счётчика = 1.

     При нажатии на кнопку «Создать потоки» создаются два потока, которые, получив соответствующие параметры, запускаются и работают, пока не выполнят функцию Execute (основная функция потока).

Процедура Execute для каждого потока содержит следующие этапы:

  1. Имитация работы потока вне критической секции в течение заданного промежутка времени.
  2. Ожидание освобождения семафора в течение  бесконечного интервала времени и его открытие сразу же после освобождения (время ожидания вычисляется и выводится в поле «числовые параметры»).
  3. Работа с критическим объектом. Время работы задается.
  4. Освобождение семафора.

     Все этапы сопровождаются вызовами процедур отображения хода работы в главном  окне программы .

     Фрагмент  модуля программы, содержащий процедуру  Execute, имеет вид:

procedure Thread1.Execute;

var

    i,j,jj,kk: integer;

    x1,x2:systemtime;

begin

  i:=1;

  randomize;

  repeat

    jj:=round(random(FSleepDuration));                - 1-й этап

    sleep(jj);

    getsystemtime(x1);

    WaitForSingleObject(Semaphore , infinite);   - 2-й этап

    getsystemtime(x2);

    UpdateGraphic(1,round(jj/k),30,cllime);

    kk:=(x2.wMinute-x1.wMinute)*60000+(x2.wSecond-x1.wSecond)*1000+(x2.wMilliseconds-x1.wMilliseconds);

    if kk>0 then UpdateGraphic(1,round(kk/k),20,clblue);

    if pos[3].X<pos[1].X then UpdateGraphic(3,(pos[1].X-pos[3].X),40,clYellow);

    j:=round(random(FWorkSemafor));   

    sleep(j);       - 3-й этап

    x:=round(random(100))+1;

    inc(i);

    WriteText:='---1---'+IntToStr(Self.ThreadID)+'-----X='+inttostr(x)+'-------Tраб.='+inttostr(jj)+'-------Tраб.кр.='+inttostr(j)+'-------Tож.='+inttostr(kk);

    UpdateGraphic(1,round(j/k),40,clred);

    UpdateGraphic(3,round(j/k),20,claqua);

    ReleaseSemaphore(Semaphore, 1, nil);   -4-й этап

    Synchronize(UpdateListBox);

  until i>10;

end;

     В программе, отображающей процедуру  Execute, используются переменные целого типа i, j, jj, kk, а также переменные системного времени (systemtime) x1 и x2. Переменная i=10 задает для каждого процесса по 10 обращений к критической секции.

     Работа  процесса вне критической секции имитируется обращением к генератору равномерно распределенных случайных чисел FSleepDuration. Число, выработанное этим генератором, присваивается переменной jj, которая и определяет длительность работы процесса перед обращением к критической секции (sleep(jj)). В окне "Числовые параметры" значение переменной jj отображает переменная Tраб.

     Момент  обращения к семафору фиксируется в переменной x1 вызовом функции системного времени: getsystemtime(x1).

     Для занятия критического ресурса производится обращение к функции WaitForSingleObject(Semaphore , infinite). Время ожидания освобождения семафора принимается равным бесконечности.

     Момент  срабатывания семафора, обеспечивающего  доступ процесса к критической секции, фиксируется в переменной x2 вызовом функции системного времени: getsystemtime(x2). Разность моментов времени x1 и x2 определяет интервал времени ожидания освобождения критической секции. Эта разность присваивается переменной kk и отображается в окне "Числовые параметры" с помощью переменной Tож.

     Работа  процесса с критической секцией  имитируется обращением к генератору равномерно распределенных случайных чисел FWorkSemafor. Число, выработанное этим генератором, присваивается переменной j, которая и определяет длительность работы процесса с критической секцией. В окне "Числовые параметры"  значение переменной j отображает переменная Tраб.кр. Новое значение переменной x, записываемое процессом в критическую секцию, вырабатывается обращением к генератору равномерно распределенных случайных чисел в диапазоне от 1 до 100. 

Ход работы 

      Каждый  из двух взаимодействующих с критическим  объектом процессов должен обратиться к нему последовательно три раза, при этом длительность работы процессов вне критической секции (Tраб) и в критической секции (Tраб.кр.) были заданы определенным вариантом (в данном случае 8).  

1-ый  процесс 2-ой процесс
Траб Траб.кр. Х Траб Траб.кр. Х
700 200 56 800 300 55
200 100 7 100 50 66
300 150 6 250 125 77
 

      Открываем файл WriterThread.pas, содержащий исходный модуль, задающий работу процессов, и вносим изменения в процедуры Thread1.Execute и Thread2.Execute.

   В исходном коде программы в процедурах Thread1.Execute и Thread2.Execute значения переменных Траб(jj), Траб.кр.(j), X задавались генератором случайных чисел (random):  

      jj:=round(random(FSleepDuration));

     j:=round(random(FWorkSemafor));

     x:=round(random(100))+1; 

     тело процедуры было заключено в цикл (repeat..until i>10), в результате наш процесс обращался к критическому объекту 10 раз при случайно заданных параметрах.

           Так как нам по условию требовалось, чтобы наши процессы обращались к критическому объекту всего 3 раза (а не 10) и использовали конкретные данные, мы внесли следующие изменении в исходный код программы (модуль WriterThread.pas ): 

    1. создали двухмерный массив данных (матрицу), в которую внесли свои данные;

      например, для 1-го процесса:

            mas[1,1]:=700;mas[1,2]:=200;mas[1,3]:=56;

         mas[2,1]:=200;mas[2,2]:=100;mas[2,3]:=7;

         mas[3,1]:=300;mas[3,2]:=150;mas[3,3]:=6; 

    1. создали вместо цикла (repeat..until i>10) цикл (For i:=1 to 3), так как процесс должен 3 раза обращаться к критическому объекту, а не 10;
    2. присвоили переменным jj,j и x данные из массива:

      jj:=mas[i,1];

      j:= mas[i,2];

      x:= mas[i,3].

       

      Так как i – это счетчик цикла, и его значения после каждого прохода цикла инкриминируются (увеличиваются) на 1, это значит, что после каждого прохода цикла программа будет брать из нашего массива (матрицы) те значения, которые были заданы моим вариантом.  
       
       
       
       
       
       
       
       
       
       
       
       

Пример  работы программы

      Потоки 
       

 

      Временная диаграмма 
       

 
 
 
 
 
 
 

Информация о работе Механизм межзадачного взаимодействия с помощью семафоров