Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ОС / Методические рекомендации по выполнению лабораторных работ.doc
Скачиваний:
243
Добавлен:
11.04.2015
Размер:
1.17 Mб
Скачать

Краткие теоретические сведения

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

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

Для синхронизации потоков системы, базирующиеся на Win32, предлагают несколько синхронизирующих объектов, основными из которых являются: критические секции (critical section), взаимные исключения (mutex – сокращение от mutual exclusion), семафоры и события. Все они кроме критических секций являются объектами ядра. Кроме того, в качестве синхронизирующих объектов могут использоваться процессы, потоки, файлы, консольный ввод, уведомления об изменении файлов.

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

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

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

Событие – это объект ядра операционной системы, который может иметь состояние «свободный» и состояние «занятый», перевод между которыми может осуществляться потоком. Используется в том случае когда некий инициирующий поток выполняет некие действия, после которых должны начать работать рабочие потоки. Пока событие занято рабочие потоки приостанавливают своё выполнение. Инициирующий поток, выполнив необходимые действия, переводит объект в «свободное» состояние. Рабочие потоки, обнаружив перевод объекта в свободное состояние, возобновляют свою работу.

К основным функциям Win32 API по управлению синхронизацией:

  • InitializeCriticalSection – инициализировать критическую секцию;

  • DeleteCriticalSection – освободить все ресурсы, включенные в критическую секцию (удалить критическую секцию);

  • EnterCriticalSection – захватить блокировку для критической секции;

  • LeaveCriticalSection – освободить блокировку для критической секции;

  • CreateMutex – создать новый мьютекс;

  • ReleaseMutex –освободить мьютекс, чтобы другой поток мог его захватить;

  • OpenMutex – открыть существующий мьютекс;

  • CreateSemaphore – создать новый семафор;

  • ReleaseSemaphore – увеличить на единицу счетчик семафора;

  • OpenSemaphore – открыть существующий семафор;

  • CreateEvent – создать новое событие;

  • OpenEvent – получить доступ к событию;

  • SetEvent – перевести событие в свободное состояние;

  • ResetEvent – перевести событие в занятое состояние;

  • PulseEvent – перевести событие в сигнализирующее (свободное) состояние, а затем вернуть в несигнализирующее (занятое);

  • WaitForSingleObject – блокироваться на одном объекте (семафоре, мьютексе и т.д.);

  • WaitForMultipleObject – блокироваться на множестве объектов, чьи дескрипторы перечисляются;

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

Пусть имеется множество процессов P={P1, P2, …, Pn}, всего n процессов и множество ресурсов E={E1, E2, …, Em}, где m – число классов ресурсов. В любой момент времени некоторые из ресурсов могут быть заняты и, соответственно, недоступны. Пусть A – вектор доступных ресурсов A={A1, A2, …, Am}. Очевидно, что Aj≤Ej, j=1, 2, …, m.

Введем в рассмотрение две матрицы:

C={cij| i=1, 2,…,n; j=1, 2,…,m} – матрица текущего распределения ресурсов, где cij – количество ресурсов j-го класса, которые занимает процесс Pi;

R={rij| i=1, 2,…,n; j=1,2,…,m} – матрица требуемых (запрашиваемых) ресурсов, где rij – количество ресурсов j-го класса, которые хочет получить процесс Pi.

Справедливо m соотношений по ресурсам:

, j=1, 2, …, m.

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

  1. Ищется процесс Pi, для которого i-я строка матрицы R меньше вектора A, то есть Ri ≤ A, или rji ≤ Aj, j =1, 2, …, m.

  2. Если такой процесс найден, это означает, что он может завершиться, а, следовательно, освободить занятые ресурсы. Найденный процесс маркируется, и далее прибавляется i-я строка матрицы C к вектору A, то есть Aj= Aj+cij, j=1,2,…,m. Возвращаемся к первому шагу.

  3. Если таких процессов не существует, работа алгоритма заканчивается. Немаркированные процессы попадают в тупик.