Вы находитесь на странице: 1из 15

76)Семафоры

Семафор - механизм реализации взаимоисключения процессов.


Пример работы двух параллельных асинхронных процессов:

Даны 2 процесса: "производитель" и "потребитель". "Производитель" вырабатывает какое-либо


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

Чтобы этого не допустить в ОС работают семафоры как для "производителя", так и для
"потребителя".
77) Критические секции.
Критическая секция (англ. critical section) — объект синхронизации потоков позволяющий
предотвратить одновременное выполнение некоторого набора операций (обычно связанных с
доступом к данным) несколькими потоками. Если вход был произведен, то ни одна другая нить
не имеет доступа к этой критической секции, выполнение будет приостановлено, а
возобновление произойдет, когда первая нить освободит критическую секцию.
78)Защита доступа к переменным
Существует ряд функций, которые разрешают работу с глобальными переменными без
синхронизации, потому что эти функции сами решают проблемы синхронизации. Это
следующие функции: InterlockedIncrement, InterlockedDecrement, InterlockedExchange,
InterlockedExchangeAdd и InterlockedCompareExchange. К примеру функция
InterlockedIncrement инкрементирует значение 32-х битной переменной.
79) синхронизация в MFC.
Библиотека MFC содержит специальные классы для синхронизации нитей (CMutex, CEvent,
CCriticalSection şi CSemaphore) Эти классы соответствуют объектам синхронизации WinAPI,
и являются производными класса CSyncObject. Для использования этих классов необходимо
обращаться к их методам и конструкторам Lock и Unlock. Другая модель использования этих
классов состоит в создании так называемых thread-safe. Класс thread-safe представляет собой
определенный ресурс. Вся работа с ресурсом реализуется в среде самого класса, который
содержит все необходимые методы. Класс спроектирован таким образом, что его методы
решают задачи синхронизации, а в рамках приложения он выглядит как обычный класс.
Функции Lock и Unlock могут быть использованы непосредственно, а в косвенном режиме через
функции CSingleLock и CmultiLock.
80) пример синхронизации в Windows.
#include <windows.h>
#include <iostream.h>

void main()
{
DWORD res;

// creăm obiectul excludere mutuală


HANDLE mutex = CreateMutex(NULL, FALSE, "NUME_APLICATIE-MUTEX01");
// dacă obiectul există deja, CreateMutex va returna descriptorul obiectul existent,
// iar GetLastError va returna ERROR_ALREADY_EXISTS

// timp de 20 s încercăm să ocupăm obiectul


cout<<"Încerc să ocup obiectul...\n"; cout.flush();
res = WaitForSingleObject(mutex,20000);
if (res == WAIT_OBJECT_0) // dacă ocupare s-a terminat cu succes
{
// aşteptăm 10 s
cout<<"L-am prins! Aşteptare 10 secunde...\n"; cout.flush();
Sleep(10000);

// eliberăm obiectul
cout<<"Acum eliberăm obiectul\n"; cout.flush();
ReleaseMutex(mutex);
}

// închidem descriptorul
CloseHandle(mutex);
}
Для проверки модуля взаимного исключения необходимо запустить два экземпляра
приложения. Первый экземпляр занимает объект и освобождает его через 10 сек. Только после
этого объект занимает второй экземпляр.
81)использование критических секций в Windows.
В этом случае критические секции используются для доступа к данным в определенный
момент времени одной нити приложения, а остальные заблокированы. Например, существует
переменная m_pObject и несколько нитей, которые вызывают методы объекта m_pObject.
Предположим, что эта переменная может время от времени изменять свое значение. Фрагмент
кода:
// Firul #1
void Proc1()
{
if (m_pObject)
m_pObject->SomeMethod();
}
// Firul #2
void Proc2(IObject *pNewObject)
{
if (m_pObject)
delete m_pObject;
m_pObject = pNewObject;
}
В этом примере существует потенциальная опасность вызова m_pObject->SomeMethod()
после чего объект будет уничтожен с помощью delete m_pObject, потому что в многозадачных
ОС выполнение любой нити может быть прервано в самый неблагоприятны для нее момент, и
начнется выполнение другой нити.
Этого можно избежать следующим образом:
// Firul #1
void Proc1()
{
::EnterCriticalSection(&m_lockObject);
if (m_pObject)
m_pObject->SomeMethod();
::LeaveCriticalSection(&m_lockObject);
}

// Firul #2
void Proc2(IObject *pNewObject)
{
::EnterCriticalSection(&m_lockObject);
if (m_pObject)
delete m_pObject;
m_pObject = pNewObject;
::LeaveCriticalSection(&m_lockObject);
}
Во время выполнения нить номер один заблокирует критическую секцию, и вторая нить получет
к ней доступ только после выполнения первой нити.
82) Structura RTL_CRITICAL_SECTION
Определена следующим образом:
typedef struct _RTL_CRITICAL_SECTION
{
PRTL_CRITICAL_SECTION_DEBUG DebugInfo; // Folosit de sistemul de operare
LONG LockCount; // Contorul de utilizări
LONG RecursionCount; // Contorul accesării repetate din firul utilizatorului
HANDLE OwningThread; // ID firului utilizatorului (unic)
HANDLE LockSemaphore; // Obiectul nucleului folosit pentru aşteptare
ULONG_PTR SpinCount; // Numărul de cicluri goale înaintea apelării nucleului
}
RTL_CRITICAL_SECTION, *PRTL_CRITICAL_SECTION;
LockCount – инкрементируется при каждом вызове ::EnterCriticalSection() и
декрементируется при каждом вызове ::LeaveCriticalSection();
RecursionCount – хранится количество повторных вызовов ::EnterCriticalSection() из
одной и той же нити.
OwningThread – содержит 0 если критические секции свободны, или идентификатор
выполняемой нити.
83) Функции API для критических областей.
функции BOOL InitializeCriticalSection(LPCRITICAL_SECTION lpCriticalSection) и BOOL
InitializeCriticalSectionAndSpinCount(LPCRITICAL_SECTION lpCriticalSection, DWORD
dwSpinCount). Заполняют поля структуры lpCriticalSection. Псевдокод функции
RtlInitializeCriticalSection din ntdll.dll
VOID RtlInitializeCriticalSection(LPRTL_CRITICAL_SECTION pcs)
{
RtlInitializeCriticalSectionAndSpinCount(pcs, 0)
}
VOID RtlInitializeCriticalSectionAndSpinCount(LPRTL_CRITICAL_SECTION pcs,
DWORD dwSpinCount)
{
pcs->DebugInfo = NULL;
pcs->LockCount = -1;
pcs->RecursionCount = 0;
pcs->OwningThread = 0;
pcs->LockSemaphore = NULL;
pcs->SpinCount = dwSpinCount;
if (0x80000000 & dwSpinCount)
_CriticalSectionGetEvent(pcs);
}
Функция DWORD SetCriticalSectionSpinCount(LPCRITICAL_SECTION
lpCriticalSection, DWORD dwSpinCount) устанавливает значение поля SpinCount и
возвращает их предыдущие значения.
VOID DeleteCriticalSection(LPCRITICAL_SECTION lpCriticalSection) освобождает
ресурсы занятые критической секцией.
VOID EnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection), BOOL
TryEnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection) – разрешает доступ в
критическую секцию.
VOID LeaveCriticalSection(LPCRITICAL_SECTION lpCriticalSection) – освобождает
критическую секцию.
84) классы критических областей.
Для корректного использования критических секций используются классы:
class CLock
{
friend class CScopeLock;
CRITICAL_SECTION m_CS;
public:
void Init() { ::InitializeCriticalSection(&m_CS); }
void Term() { ::DeleteCriticalSection(&m_CS); }

void Lock() { ::EnterCriticalSection(&m_CS); }


BOOL TryLock() { return ::TryEnterCriticalSection(&m_CS); }
void Unlock() { ::LeaveCriticalSection(&m_CS); }
};

class CAutoLock : public CLock


{
public:
CAutoLock() { Init(); }
~CAutoLock() { Term(); }
};

class CScopeLock
{
LPCRITICAL_SECTION m_pCS;
public:
CScopeLock(LPCRITICAL_SECTION pCS) : m_pCS(pCS) { Lock(); }
CScopeLock(CLock& lock) : m_pCS(&lock.m_CS) { Lock(); }
~CScopeLock() { Unlock(); }
void Lock() { ::EnterCriticalSection(m_pCS); }
void Unlock() { ::LeaveCriticalSection(m_pCS); }
};

Классы Clock и CAutoLock используются как правило для синхронизации доступа переменных
классов, а CScopeLock предназначен для использования в процедурах.
85) Устранение повреждений критических секций
Устранение повреждений критических секций является весьма сложным процессом. Ошибки
критических секций бывают двух типов: ошибки реализации и архитектурные ошибки. Ошибки
реализации как правило легко обнаружить. Они возникают при вызове ::EnterCriticalSection() и
::LeaveCriticalSection()
void Proc()
{
m_lockObject.Lock();
if (!m_pObject)
return;
// ...
m_lockObject.Unlock();
}
Здесь пропущен вызов ::LeaveCriticalSection().
Из архитектурных ошибок наиболее распространенная роковое объятие (deadlock) когда две
нити пытаются одновременно получить доступ к двум и более критических секций.
void Proc1()
// Firul #1
{
::EnterCriticalSection(&m_lock1);
// ...
::EnterCriticalSection(&m_lock2);
// ...
::LeaveCriticalSection(&m_lock2);
// ...
::LeaveCriticalSection(&m_lock1);
}

// Firul #2
void Proc2()
{
::EnterCriticalSection(&m_lock2);
// ...
::EnterCriticalSection(&m_lock1);
// ...
::LeaveCriticalSection(&m_lock1);
// ...
::LeaveCriticalSection(&m_lock2);
}
Важно:
- Критические секции выполняются относительно быстро и не требуют много ресурсов от
системы;
- Для синхронизации доступа нескольких независимых переменных лучше использовать
несколько критических секций (а не одну для всех переменных);
- код критической секции должен быть сведен к минимум;
- не рекомендуется вызывать из критической секции «чужие» объекты.
86. Администрирование процессов предполагает управление и синхронизацию в рамках
некоторой операционной системы. Используемые механизмы основаны на реализации принципа
взаимного исключения.
Реализация взаимного исключения. Механизмы, реализующие взаимное исключение для
некоторого набора программ основаны на общем принципе: использование механизма
взаимоисключений действующего уже на нижнем уровне. В результате используются общие
переменные конкурирующих процессов, а связанность этих переменных должна быть
гарантированной. На базовом уровне существуют два элементарных механизма: взаимного
исключения доступа к одному участку памяти и маска прерываний. Это основные механизмы,
но на уровне физических ресурсов или микропрограмм существуют более сложные устройства,
например инструкции Test and test или семафоры.
Спецификация задачи. Файл {p1, p2,...,pn} – множество процессов, которые мы считаем циклами;
программа каждого процесса содержит критическую секцию. Взаимное исключение
застраховано двумя фрагментами (prolog,epilog), которые внедряют критическую секцию
каждого процесса. Предположим, что каждый процесс, который входит в критическую секцию,
покидает ее за конечный интервал времени.
Решения должны обладать следующими свойствами:
А) взаимное исключение – в каждый момент времени более одного процесса выполняют
критическую секцию (?????????)
Б)Снисходительность к неполадкам – решение должно оставаться действующим и в случае
некоторых ошибок в одном или более процессов, которые находятся вне критической секции.
В) процесс, который требует входа в критическую секцию не должен ожидать бесконечно.
Г) симметричность – prolog и epilog должны быть идентичными для всех процессов и
независимы от их количества.

87. процесс в активном ожидании имитирует блокировку повторного тестирования состояния


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

88. Алгоритм Деккера.


В начале предположим что существуют два процесса p0 и p1.
Первое рассмотрение состоит в представлении состояния ожидания, (который является
дополнением состояния переполнения) некоторой булевой переменной с. Тогда имеем:
С = «процесс находится в критической зоне»
В таком случаем можно предложить следующую программу:
iniţializare: c := false;
prolog : test: if c then
go to test
else
c := true
endif;
<secţiunea critică>
epilog : c := false;
алгоритм деккера тем не менее может быть сконструирован без использования механизма
взаимоисключений, вне неделимости доступа к чтению или актуализации некоторого участка
памяти.
Ниже приведен алгоритм, который может быть расширен для произвольного кол-ва процессов:
//программа использует три переменные для управления двумя процессами.
var c:array [0..1] of boolean;
tur:0..1;
iniţializare:c[0]:=c[1]:=false;
tur:=0;
prolog: -- pentru procesul i; se va pune j=1-i (celălalt proces)
c[i]:=true;
tur:=j;
test:if c[j] and tur=j then
go to test
endif;
...
epilog : -- pentru procesul i
c[i]:=false;

89. Для обработки с помощью метода активного ожидания случая, в случае, когда несколько
процессов инициируют и обращаются к общим переменным, некоторые машины имеют
инструкцию, которая реализует способ неделимого обращения и актуализации некоторого
участка памяти. Эта инструкция называется Test And Set (tas), эта инструкция используется в
мультипроцессорных системах. В однопроцессорных системах маскировки прерывания
достаточно для страховки взаимоисключений.
90. Семафор – Элементарный инструмент для взаимного исключения. Определения.
Семафор s образован соединением некоторого счетчика с целочисленными значениями,
обозначенного s.c. и некоторой нити ожидания, обозначенной s.f. При создании семафора
счетчика i приписывается исходное значение s0 (s0>0) и нить ожидания является пустой.
Семафор обслуживает блокировку процессов, ожидающих создания условий для их
разблокировки. Заблокированные процессы помещаются в нить ожидания s.f. Один процессор
может оперировать только с помощью двух операций P(s) и V(s), называемых примитивами.
Значение счетчика и состояние нити ожидания недоступны даже для чтения. Существует
процесс p который выполняет P(s) или V(s), и процесс q, который находится в нити ожидания.
Алгоритм примитивов следующий: P(s): V(s):
s.c.:=s.c.-1; s.c.:=s.c.+1;
if s.c.<0 then if s.c.≤0 then
stare(p):=blocat; extragere(q,s.f.);
introducere(p,s.f.) stare(q):=activ
endif endif

91. Семафор - свойства.


Основные свойства синхронизации с помощью семафора могут быть выведены из нескольких
инвариантных отношений: отношения контролирующие инициализацию, и которые остаются
неизменными после выполнения примитивов P(s) или V(s) произвольное количество раз.
1) Для семафора s существует:
np(s) – Общее количество операций P(s),
nv(s) – Общее количество операций V(s).
Имеет место отношение:
s.c. = s0 – np(s) + nv(s)
потому что начальное значение s.c. = s0. Каждая операция P(s) уменьшает это значение на
единицу, а V(s) увеличивает на единицу.
2) Существует nbloc(s) количество заблокированных процессов в s.f. Имеет место отношение
nbloc(s) = if s.c. ≥ 0 then 0 else –s.c. endif
которое можно записать виде nbloc(s) = max(0, –s.c.).
3) Отношение 2 можно записать в другой форме. Существует nf(s) количество «переходов» к
процессам примитива P(s), т.е. сумма количества выполнения P(s) без блокировок и количество
разблокировок V(s). В конечном итоге получаем nf(s) = min(np(s), s.c.+nv(s)).
92) Реализация взаимного исключения с помощью семафора.
Этот метод решает вопрос взаимного исключения для n процессов.
Существует nc количество процессов, находящихся в критической секции в конкретный
момент времени. Имеем:
nc = nf(mutex) – nv(mutex) (4)
в этом случае свойства могут быть проверены применением семафора mutex .
nf(mutex) = min(np(mutex), 1+nv(mutex)) (5)
А)Взаимное исключение
Из (5) имеем:
nf(mutex) ≤ 1+nv(mutex)
и, используя (4), получаем nc ≤ 1: взаимное исключение гарантировано.
Б) отсутствие блокировок.
Предположим, что ни один процесс не находится в критической секции. В этом случае nc =
0,или
nf(mutex) = nv(mutex) sau încă
nf(mutex) ≤ 1+nv(mutex)
Согласно отношению (5):
nf(mutex) = np(mutex) sau
nbloc(mutex) = 0

Включенные критические секции временная траектория выполнения процессов может привести


к состоянию, когда оба процесса заблокированы на бесконечное время, так как могут быть
разблокированы только другим. Эта ситуация называется роковым объятием.
Бесконечное ожидание в критической секции или тупик блокировка неправильных или
бесконечных циклов, которые находятся в критической секции, могут парализовать выполнение
других процессов. В случае глобальной критической секции, реализация для операционной
системы может быть следующей:
- Любому процессу, выполняющему глобальную критическую секцию задается на все время
выполнения специальный статус, который выделяет определенные права.
Лишения.
Алгоритм взаимных исключений гарантирует вход процесса в критическую секцию, если много
процессов пытаются выполнить это, когда критическая секция свободна. Может случиться, что
особый процесс будет задержан на неограниченное время: этот феномен называется лишением.

93) Функционирование и структура ядра синхронизации. Состояния процесса. Нить


ожидания.
Понятия процесс и ассоциативная операция как правило не являются частью набора основы
компьютера. Они могут быть имплементированы с помощью некоторых программ и/или
микропрограмм, которые формируют ядро администрирования процессов. В рамках описания
операционной системы с помощью абстрактных механизмов иерархии, ядро составляет самый
низший уровень, реализованный непосредственно на физической машине.
Свойства:
- понятие процесс, которое эквивалентно понятию виртуальный процесс, скрывает
использование ядра физическим процессом.
- примитивы синхронизации, реализованные в ядре, скрывают физические механизмы
коммутации контекста, например требование прерывания.
Структура ядра синхронизации зависит от спецификации физической машины (запрос
прерывания, структура слова состояния, одно- или многопроцессорная система и т.д.) и от
спецификации абстрактной машины, которую необходимо реализовать, особенно механизм
синхронизации.
Состояние процесса . процесс может находится в двух состояниях – активный или
заблокированный. Активное состояние в свою очередь подразделяется на два состояния –
выбран – когда процесс выполняется в данный момент времени на физическом процессор; готов
- когда не может бытьт выполнен по причине отсутствия свободного процессора.
eligib
(1)
il ales
(read (2) (exe)
y)
(4) (3)

blocat
(wait)
Fig.4.1. Stările unui
proces
Переходы (3) и (4) - внутренние переходы. Управляемые синхронизацией процессов.
Переходы (1) и (2) – «технологические» переходы на физическом уровне процессора.
Если предположить, что следующий выбранный процесс будет всегда первым из нити
процессов в состоянии ready, алгоритм выделения может быть определен:
- с помощью алгоритма включения в нить процессов ready;
- с помощью алгоритма, определяющего отказ физического процессора.
Множество программ, которые реализую эти алгоритмы называются планификатором
(scheduler).
Программа, которая реализует выбор называется диспетчером.

planificator
fire de procese
blocate
dispecer proces ales
firul proceselor eligibile
Fig.4.2. Fire de aşteptare ale proceselor, administrate de nucleul sistemului
de operare
94) Администрирование контекста и схемы примитивов
Операция выделения физического процесса сохраняет копию контекста. Эта копия сохраняет
состояние процессора. Каждому процессу сопоставляется резидентный участок памяти который
называется вектор состояния, блок управления процесса или блок контекста, который включает:
- информация о состоянии процессора;
- значения атрибутов процесса;
- указатели на выделенное пространство;
- управляющая информация.
Организация ядра.
Выполнение программ ядра определено в двух модулях:
- через выбор примитива управления процессом
- через прерывания
В обоих случаях механизм входа в ядро сохраняет слово состояния процессора и его регистры.
alocare procesor apelare supervizor
proces

programul
nucleului

periferice,
lansare ceasul întreruperi

Fig.4.3. Comunicarea cu un nucleu de sincronizare


Программа примитива:
prolog; -- сохранение контекста и слова состояния
control; -- проверка прав и параметров
<corpul programului> -- управление нитями процесса
alocare_procesor; -- программа-диспетчер и выход из критической секции.
Схемы обработки прерываний механизмом синхронизации
1) Инициализация процесса, обрабатывающего прерывания.
2) Инициализация операции разблокировки (semnalizare сопоставленное условию V)
прерывания..

96. Реализация ядра синхронизации. Интерфейсы.


А) Управление процессами.
Процессs могут быть созданы и уничтожены в динамическом режиме и организованы
иерархически в соответствии отношению связей. Процесс создается с помощью примитива
creare(p, context iniţial, atribute) атрибуты включают приоритет и права доступа. Исходный
контекст определяет исходное состояние слова состояния и регистров процессора. Процесс
создается в состоянии ready.
Процедура уничтожения может быть применена к процессу для самоуничтожения.
Процедура suspend(p) прерывает выполнение процесса, помещая его в специальную нить
ожидания. Выполнение процесса может быть возобновлено с помощью примитива reluare(p).
Использование примитивов creare, distrugere, suspendare şi reluareобусловлено правами,
которые определены атрибутом права процесса.
Б) Синхронизация. Процессы синхронизируются с помощью мониторов. Управление мониторов
интегрировано в механизм монитора. Мониторы определены в программах процессов, монитор
создается при компиляции программы.
97. Реализация ядра синхронизации. Структуры и алгоритмы.
С момента создания процесса ему сопоставляется фиксированный номер (хэндл), который
служит для его обозначения и открывает доступ своего блока контекста. Блок контекста
содержит следующие поля:
Csp : зона сохранения слова состояния процессора,
Reg : зона сохранения главныхрегистров процессора,
Stare : значение состояния процесса (ready, wait, ...),
Prio : приоритет процесса,
Drepturi : права процесса,
Fire, etc. : цепная связь в иерархии процессов,
Suc, etc. :цепная связь в нитях ожидания (FA).
Администрирование процессов использует нити ожидания, заданные в порядке уменьшения
приоритета и управляемые набором процедур доступа.
introducere(p, f) Ввод p în f.
primul(f) Возвращает хэндл процесса из вершины f (nil если f пусто); не изменяет f.
ieşire(p, f) Извлекает из нити f первый процесс, его описатель будет передан p (nil если f
пусто).
vid(f) булевая функция, true если нить f пуста, false в противном случае.
..
.
legătură de
Csp[i] înlănţuire

Bloc Reg[i]
de
contex Stare[i]
t
Drepturi legături de
[i] înlănţuire în
context în
blocul FA
Prio[i] memorie
.. contextului
. Fig.4.4. Organizarea unui
i
FA de procese
98)Реализация мониторов.
А)семантика примитива semnalizare. Спецификация примитива c.semnalizare заключается во
временном переходе процесса, выполняющего примитив semnalizare в состояние блокировки.
Разблокированный процесс переходит в состояние ready и требует входа в монитор. Условие
провоцирующее разблокировку может быть изменено до того, как сам процесс разблокирован.
if continuare_non_posibilă then
c.aşteptare
endif
В этом случае:
while continuare_non_posibilă do
c.aşteptare
endwhile

б) множественная разблокировка. Вопрос множественной разблокировки может быть решен


введением нового примитива c.difuzare_semna, действие которого заключается в следующем:
while c.non_vid do
c.semnalizare
endwhile
Все разблокированные процессы будут проверены новым условием и затребуют снова доступ к
монитору
В) Барьерное запаздывание.
Из проблемы безопасности, именно для обработки блокировок может быть использовано
условие барьерного запаздывания монитора. Это запаздывание равно максимальной
длительности блокировки процесса в нити ожидания сопоставленной данному условию. Для
окончания барьерного запаздывания может быть использована специальная обработка. Эта
обработка может заключаться в простой разблокировке процесса или переводе на специальную
нить ожидания. Существует M.c.întârziere барьерное запаздывание сопоставленное условию c в
мониторе M. Инструкция: hdeblocare[p]:=habs+M.c.întârziere hdeblocare – новое поле контекста.

99) Базовые алгоритмы. Программа-монитор должна выполнять:


 Взаимное исключение для процедур монитора,
 Блокировка и разблокировка примитивов aşteptare и semnalizare.
Каждый монитор M содержит следующие структуры данных:
 Устройство взаимного исключения M.disp (lacăt), которое может принимать два значения
liber и ocupat, и нить ожидания M.fir. первоначально M.disp=liber, M.fir=<vid>.
 Каждому условию c сопоставлена нить M.c.fir, счетчик M.c.întârziere и при условии
прерывания булев индикатор M.c.într_sosită.
Процедура управления устройством:
cerere_disp(M, p): eliberare_disp(M):
if M.disp=ocupat then if vid(M.fir) then
intrare(p, M.fir); M.disp:=liber
stare[p]:=blocat else
else ieşire(q, M.fir);
M.disp := ocupat; intrare(q, f_eligibil);
intrare(p, f_eligibil); stare[q]:=eligibil
stare[p]:=eligibil endif
endif

intrare(M): ieşire(M):
prolog; prolog;
p:=<proces apelant>; p:=<proces apelant>;
cerere_disp(M, p); eliberare_disp(M);
alocare_procesor; intrare(p, f_eligibil);
alocare_procesor;
c.aşteptare: c.semnalizare:
prolog; prolog;
p:=<proces apelant>; p:=<proces apelant>;
intrare(p, M.c.fir); if non_vid(M.c.fir) then
stare[p]:=blocat; ieşire(q, M.c.fir);
eliberare_disp(M); cerere_disp(M, p);
alocare_procesor; cerere_disp(M, q);
eliberare_disp(M)
else
intrare(p, f_eligibil)
endif
alocare_procesor;
последовательность prolog обеспечивает сохранение контекста и входа в критическую секцию.
alocare_procesor обеспечивает выделение процессора и защиту критической секции.
100) обработка прерваний.
Для защиты информации механизмы синхронизации любого прерывания содержат:
 Условие в некотором мониторе,
 Циклический процесс, который реализует обработку прерываний.
Условие может быть сопоставлено единственному уровню прерывания. Вызов прерывания
запускает функцию сигнализации для определенного условия. Относительный приоритет
прерываний транслируется в приоритет процессов, которые его обрабатывают. Может
возникнуть ситуация, когда прерывание будет вызвано в тот момент, когда процесс,
обрабатывающий это прерывание, находится в состоянии выполнения и прерывание будет
утеряно. Чтобы этого не происходило используется специальный булев индикатор,
регистрирующий прерывания.
ciclu
test if nonM.c.într_sosită then
c.aşteptare; -- evitarea pierderii unei întreruperi
go to test
endif;
<tratarea întreruperii>
endciclu
<sosirea unei întreruperi asociate lui M.c>
M.c.într_sosită := true;
c.semnalizare;
101) Обработка ошибок.
Принцип обработки ошибок состоит в блокировке процесса, спровоцировавшего
возникновение ошибки, и отправки сообщения родительскому процессу. Для этого используется
специальная нить f_eroare. Ошибка, возникающая при выполнении некоторого процесса,
провоцирует отклонение, которое может быть обработано следующим образом:
prolog;
p:=<proces apelant>;
intrare(p, f_eroare);
<tratare specifică>;
stare[p]:=suspendat;
alocare_procesor;
Определяется новое состояние suspend, которое применяется к процессу, выполнение которого
было прервано прерыванием.
103) Создание и уничтожение процесса
Главная проблема динамического управления процессами это выделение контекста и описателя процесса. Для
этого используются два основных метода:
 Для блоков контекста зарезервирован фиксированный номер месторасположения;
неиспользованное место определено специальным значением (nil) поля состояния;
 Места, зарезервированные блокам контекста выделяются динамически в памяти; номера
выделяются процессам тоже в динамическом режиме, в специальной таблице номер процесса
сопоставляется адресу в памяти его блока контекста.
В обоих случаях используется процедура alocare_context(p), которая реализует выделение контекста и
возвращает номер p процесса. Номер созданного процесса возвращается в результате выполнения следующего
примитива:
creare(p, context iniţial):
prolog;
control; -- verificarea drepturilor
alocare_context(p);
if p ≠ nil then
iniţializare_context(i);
intrare(p, f_eligibil)
endif;
intrare(proces apelant, f_eligibil);
alocare_procesor; -- este întors p drept rezultat

исходный контекст определен создавшим его процессом: ему необходимо определить исходное состояния
регистров и слова состояния процессора, состояние рабочего пространства и атрибутов.
Для уничтожения процесса необходимо освободить ранее выделенные ресурсы. Этим управляет непосредственно
ядро. Уничтожение процесса, находящегося в критической секции может привести к блокировке. Критические
секции мониторов управляются непосредственно ядром.
Принцип примитива уничтожения:
distrugere (p):
prolog;
control; -- verificarea drepturilor
eliberare_context(p);
intrare(proces apelant, f_eligibil);
alocare_procesor;
Процедура eliberare_context(p) должна обеспечить освобождение ресурсов используемых уничтожаемым
процессом.

eliberare_context(p):
listă:=<lista firelor procesului p>;
restituire_bloc_context(p);
restituire_memorie(p);
for q∈ listă do
eliberare_context(q)
endfor;

----------------------------------------------------------------------------------------------------------

104) Прекращение и возобновление. Примитив suspend разрешает родительскому процессу


контролировать деятельность дочернего процесса, прерывая в принудительном режиме его выполнение.
Использование – приостановка процесса включенного в бесконечный строб. Прерванный таким образом процесс
переводится в специальную нить ожидания, которой может быть нить f_eroare, используемая для сдвига.
Приостановка процесса имеет аналогичные проблемы как и его уничтожение, когда процесс находится в
критической секции монитора:
suspendare(p):
prolog;
control;
< tratare secţiune critică>;
f:=<fir care conţine p>;
extragere(p, f);
intrare(p, f_eroare);
stare[p]:=suspendat;
intrare(proces apelant, f_eligibil);
alocare_procesor;
Примитив reluare разрешает процессу разблокировать приостановленную нить после
возможного изменения своего контекста.
reluare(p):
prolog;
control;
extragere(p, f_eroare);
stare[p]:=eligibil;
intrare(proces apelant, f_eligibil);
intrare(p, f_eligibil);
alocare_procesor;

Вам также может понравиться