Примечание и предостережение

В данном примере преднамеренно и полностью осознанно употребляется функция PulseEvent, хотя некие создатели, а где-то и документация Microsoft (см. замечания в соответственном разделе MSDN), этого делать не советуют. Предпосылки нашего выбора будут ясны из следующего обсуждения и подкреплены примерами, а читателю предлагается решить (корректно) эту задачку, используя функцию SetEvent.

typedef struct Примечание и предостережение _state_t {

HANDLE Guard; /* Мьютекс, защищающий объект. */

HANDLE CvpSet; /* Вручную сбрасываемое событие — производится условие, определяемое предикатом cvp(). */

… другие переменные критерий …

/* Структура состояния, содержащая счетчики, контрольные суммы и прочее. */

struct STATE_VAR_TYPE StateVar;

} STATE_TYPE State;

/* Инициализировать состояние, создавая мьютекс и событие. */

/* Поток ПРОИЗВОДИТЕЛЯ, который изменяет состояние. */

WaitForSingleObject Примечание и предостережение(State.Guard, INFINITE);

/* Поменять состояние таким макаром, чтоб производилось условие, */

/* определяемое предикатом CV. */

/* Пример: к данному моменту подготовлено одно либо несколько сообщений.*/

State.StateVar.MsgCount += N;

PulseEvent(State.CvpSet);

ReleaseMutex(State.Guard);

/* Конец интересующей нас части кода потока производителя. */

/* Ожидание определенного состояния функцией потока ПОТРЕБИТЕЛЯ. */

WaitForSingleObject(State.Guard, INFINITE Примечание и предостережение);

while (!cvp(&State)) {

ReleaseMutex(State.Guard);

WaitForSingleObject(State.CvpSet, TimeOut);

WaitForSingleObject(State.Guard, INFINITE);

}

/* Сейчас этот поток обладает мьютексом, и производится условие, */

/* определяемое предикатом cvp(&State). */

/* Сделать соответственное действие, может быть, изменяя состояние.*/

ReleaseMutex(State.Guard);

/* Конец интересующей нас части кода потока потребителя. */

Комменты по поводу модели переменных критерий

В приведенном Примечание и предостережение выше куске кода очень принципиальная роль принадлежит циклу в той части кода, которая соответствует потребителю. Этот цикл включает три операции: 1) освобождение мьютекса, заблокированного до входа в цикл; 2) ожидание действия; 3) повторное блокирование мьютекса. Как будет показано дальше, внедрение конечного интервала ожидания действия является очень значимым.

Потоки Pthreads в Примечание и предостережение том виде, в каком они реализованы в почти всех системах UNIX и других системах, соединяют эти три операции в одной функции — pthread_cond_wait, объединяющей мьютекс и переменную условия (которая подобна, но не схожа событиям Windows). Вот поэтому и употребляется термин модель переменных критерий. Существует также версия этой функции, допускающая Примечание и предостережение внедрение конечных интервалов ожидания событий.

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

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

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

Примечание

В версии Windows NT 4.0 была введена новенькая функция — SignalObjectAndWait (SOAW), которая делает упомянутые два шага атомарным образом Примечание и предостережение. В последующих примерах программ подразумевается, что эта функция доступна, и она будет употребляться, а это значит, что под управлением Windows 9x такие программки производиться не сумеют. Все же, на стадии ознакомления с моделью CV функция SOAW не применяется, чтоб сделать более понятной мотивировку необходимости ее использования потом, а на Примечание и предостережение Web-сайте книжки приведены другие варианты реализации неких примеров, в каких заместо мьютексов употребляются объекты CS. (Функцию SOAW нельзя использовать совместно с объектами CS.) О значимых преимуществах функции SignalObjectAndWait в отношении производительности свидетельствуют данные, выставленные в приложении В (табл. В.5).

Внедрение модели переменных критерий

Модель переменных критерий при Примечание и предостережение правильной ее реализации работает последующим образом:

• Поток производителя перекрывает мьютекс, изменяет состояние, применяет к событию функцию PulseEvent, когда это нужно, и разблокирует мьютекс. К примеру, функция PulseEvent может вызываться в случае готовности 1-го либо нескольких сообщений.

• Функция PulseEvent должна применяться к событию при блокированном мьютексе, чтоб никакой другой Примечание и предостережение поток не мог поменять объект, что могло бы сделать недействительным условие, определенное предикатом.

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

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

• Интервал ожидания действия должен быть конечным, чтоб обеспечить правильную обработку в этом случае, если поток производителя применит к событию функцию PulseEvent в промежутке времени меж освобождением мьютекса (шаг 1) и выполнением ожидания действия (шаг 2). Таким макаром, без использования Примечание и предостережение конечного интервала ожидания сигнал мог бы потеряться, что является еще одним примером проявления трудности состязательности. К потере сигналов могут приводить и асинхронные вызовы процедур, описанные дальше в этой главе. Применяемый в приведенном выше куске кода интервал ожидания является настраиваемым параметром. (С комментами по поводу хороших значений Примечание и предостережение этого параметра вы сможете ознакомиться, обратившись к приложению В.)

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

• После выхода из цикла поток потребителя всегда сохраняет за собой право владения мьютексом, независимо от того, производилось либо не производилось тело цикла.

Разновидности модели переменных критерий

Сначала, направьте внимание на то, что Примечание и предостережение в предыдущем куске кода употребляется сбрасываемое вручную событие и вызывается функция PulseEvent, а не функция SetEvent. Является ли таковой выбор корректным и вероятен ли другой метод использования действия? Ответ на оба эти вопросы является положительным.

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

Из 4 вероятных композиций, обозначенных в табл. 8.1, для модели переменных критерий важны только две. Что касается 2-ух других композиций, то в силу конечности интервала ожидания эффект композиции "автоматом сбрасываемое событие/PulseEvent" будет этим же, что и Примечание и предостережение композиции "автоматом сбрасываемое событие/SetEvent" (сигнальная модель CV), но зависимость от продолжительности интервала ожидания приведет к понижению черт реактивности.

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

Подводя итоги, можно прийти к выводу, что композиция "автоматом сбрасываемое событие/SetEvent" представляет собой сигнальную модель CV, в какой освобождается единственный из ожидающих потоков, а композиция "вручную сбрасываемое событие/PulseEvent" — широковещательную модель CV, в какой освобождаются все ожидающие потоки. Для Примечание и предостережение потоков Pthreads есть те же различия, но внедрение конечных интервалов ожидания событий для широковещательной модели в этом случае не требуется, тогда как в Windows этот фактор является очень значимым, так как освобождение мьютекса и ожидание действия не производятся атомарно, другими словами за одну операцию. В то же время, введение Примечание и предостережение функции SignalObjectAndWait меняет эту ситуацию.

Пример предиката переменной условия

Разглядим последующий предикат переменной условия:

State.StateVar.Count >= K;

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

Заметьте, что в этом случае подходит широковещательная модель CV Примечание и предостережение, так как один поток производителя может прирастить значение счетчика и тем разрешить выполнение нескольким, но не многим ожидающим потокам потребителя.

Семафоры и модель переменных критерий

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

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


prilozheniya-prikaz-rukovoditelya-organizacii-metodicheskie-rekomendacii-po-provedeniyu-zanyatij-s-rabotayushim-naseleniem.html
prilozheniya-prilozhenie-1-klassifikaciya-it-koncepciya-razvitiya-otrasli-informacionnih-tehnologij-rf-ministerstvo.html
prilozheniya-prilozhenie-1-metodicheskie-ukazaniya-po-realizacii-voprosov-mestnogo-samoupravleniya-vsfere-kulturi.html