Чем вытесняющая многопоточность выгоднее механизма диспетчеризации, используемого в 16-ти разрядном Windows 3.x?
Основная экономия заключается в том, что переключение контекста происходит реже, не каждый раз, как истечет квант времени. Если по истечении кванта не найдется потока с большим приоритетом, или больший приоритет будет у потока, работающего в том же самом процессе, то контекст переключать не надо. А в Windows 3.x переключение происходи по циклу при каждом кванте.
Синхронизация потоков (продолжение)
Давайте рассмотрим оставшиеся механизмы синхронизации потоков. Итак, мы уже знакомы со взаимоисключением и семафорами. Помимо этого в ОС используются мониторы.
Мониторы
Это механизм синхронизации процессов (потоков), который содержит как данные, так и процедуры, необходимые для реализации динамического распределения конкретного общего ресурса. Чтобы обеспечит выделение нужного ему ресурса, процесс должен обратиться к конкретной процедуре монитора. Естественно, что необходимость получить доступ к ресурсу может возникнуть одновременно у нескольких процессов. Но вход в монитор находится под контролем - здесь осуществляется взаимоисключение процессов. В каждый момент времени только одному процессу разрешается войти в монитор. Процессам, которые хотят войти в монитор, придется ждать, если он уже занят. Причем, в отличии от семафоров, процессом ожидания управляет сам монитор.
Внутренние данные монитора доступны только изнутри его. Подобный пример инкапсуляции данных и обрабатывающих эти данные процедур мы с Вами еще рассмотрим при изучении ООП.
Итак, для того, чтобы синхронизировать вход в монитор, применяется уже известный нам механизм исключения.
Например,
Lock::Acquire - ожидать, пока критический участок не освободится, а затем захватить его.
Lock::Release - освободить, разбудить процесс, который ожидает в функции Acquire.
Вспомним правила взаимоисключения:
n прежде чем получить доступ к разделяемым данным, необходимо осуществить исключение доступа к ним других
n после завершения обработки разделяемых данных необходимо освободить их и тем самым разрешить их захват другим процессам для обработки.
Простой пример синхронизации при обработке списка:
AddToQueue ()
{
lock.Acquire(); // захватить перед обработкой
PutItemToQueue(); // Обработать разделяемые данные
lock.Realise(); // Освободить после обработки
}
RemoveFromQueue()
{
lock.Accuire();
if(AnythingIsInQieue()) RemoveItemFromQueue();
lock.Realise();
}
Все хорошо? А если в списке нет данных? Как надо изменить RemoveFromQueue() чтобы эта функция могла подождать, чтобы данные появились в списке.
Вообще то, можно было бы подождать (уснуть) внутри критической секции, но тогда, если запереть секцию, пока ждем, то как же кто-либо в нее войдет, чтобы добавить элемент в список?
Новая идея: пускай спит внутри критической секции (раз уж вошла в нее, не выгонять же теперь), но пусть “отопрет “ вход в нее на то время, пока спит. Как это сделать? Для этого придумали условные переменные (переменные-условия). Это очередь потоков, которые ожидают входа в критическую секцию. Условные переменные поддерживают три операции:
Wait() - освободить исключение, “уснуть”, перехватить исключение. Освобождение исключения и засыпание являются непрерывными (atomic).
Signal() - Разбудить спящего, если что-то произошло
Broadcast() - разбудить всех спящих
При выполнении условных операций критическая секция должна быть захвачена.
Модифицируем пример синхронизации с использованием условных переменных.
AddToQueue ()
{
lock.Acquire(); // захватить перед обработкой
PutItemToQueue(); // Обработать разделяемые данные
condition.signal(lock); // оповестить ожидающего об освобождении данных
lock.Realise(); // Освободить после обработки
}
RemoveFromQueue()
{
lock.Accuire();
// if(AnythingIsInQieue())
while (!(AnythingIsInQieue()) condition.wait (&lock); // освободить, уснуть, проснуться после сигнала
RemoveItemFromQueue();
lock.Realise();
}
Поскольку у процесса могут быть различные причины для ожидания в мониторе, то для каждой отдельной причины назначается собственная условная переменная (в рассмотренном случае - lock).
Уважаемый посетитель!
Чтобы распечатать файл, скачайте его (в формате Word).
Ссылка на скачивание - внизу страницы.