Вход/Регистрация
Интернет-журнал "Домашняя лаборатория", 2007 №6
вернуться

Журнал «Домашняя лаборатория»

Шрифт:

Это случай соответствует реентерабельному контексту или невложенному вызову.

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

• IsNestedCall(work._reqMsg) == true

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

Другая возможность — инкапсулированный вызов является вложенным для исходящего асинхронного вызова. Но можно ли этот инкапсулированный вызов исполнять вне очереди и в этом случае? Отложим обсуждение этого вопроса.

Итак, в первом случае (не вложенный вызов), поток входит в критическую секцию

lock(work) {

……

}

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

lock(_workltemQueue) {

……

}

Войдя в эту вторую критическую секцию, поток проверяет — имеется ли блокировка домена синхронизации. Поле _locked атрибута синхронизации равно false в том случае, когда после выполнения очередной работы обнаруживается, что очередь работ пуста, то есть нет работы, которую следует начинать выполнять в рамках данного домена синхронизации.

Если домен синхронизации не заблокирован, и очередь работ пуста, то домен блокируется, но флаг постановки работы в очередь bQueued не задается (работа может быть выполнена сразу же):

if ((!_locked) &&

(_workltemQueue.Count == 0)) {

_locked = true;

bQueued = false;

}

В противном случае задается флаг bQueued постановки работы в очередь, в самой работе задается флаг, указывающий на то, что она стоит в очереди (work.SetWaiting ) и выполняется реальная запись работы в очередь:

else {

bQueued = true;

work.SetWaiting;

_workltemQueue.Enqueue(work);

}

Теперь поток выходит из второй (внутренней) критической секции, разблокировав очередь работ. Но что ему делать дальше?

Если работа была поставлена в очередь, то в силу синхронности вызова данный поток должен сам перейти в состояние ожидания, из которого он выйдет только тогда, когда только что поставленная в очередь работа продвинется в ее начало и будет готова для выполнения:

if (bQueued == true) {

Monitor.Wait(work);

if (!work.IsDummy) {

DispatcherCaiiBack(null, true);

}

else {

lock(workltemQueue) {

_workltemQueue.Dequeue;

}

}

}

Вызов Monitor.Wait (work) переведет текущий поток в состояние ожидания, причем этот поток освободит ранее заблокированную им работу work и будет ожидать сигнала, говорящего о том, что состояние объекта work изменилось, нужно проснуться и продолжить работу с этим объектом. Это сигнал будет выдан другим потоком, заметившим, что работа work первая в очереди и нет препятствий для ее выполнения.

Следующая за Monitor.Wait(work); строка кода будет выполняться уже разбуженным потоком, который вновь получает исключительный доступ к объекту work. Если данная работа не является работой-заглушкой (об этом позже), то вызывается уже рассмотренный метод DispatcherCallBack, который и извлечет эту работу из очереди, выполнит ее и инициирует выполнение следующей работы. В случае же работы-заглушки просто блокируется очередь работ и эта работа-заглушка удаляется из очереди.

А вот что происходит с работой, которую не пришлось ставить в очередь:

else {

if (!work.IsDummy) {

work.SetSignaled;

ExecuteWorkltem(work);

HandleWorkCompletion;

}

}

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

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

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

if (!IsNestedCall(work._reqMsg)) {

}

else {

work.SetSignaled;

work.Execute;

}

Тут устанавливается флаг готовности к выполнению, работа выполняется, но никакой подготовки к выполнению следующей работы не проводится, т. к. уже имеется находящийся в состоянии выполнения вызов, ожидающий выполнения данного синхронного вызова.

  • Читать дальше
  • 1
  • ...
  • 315
  • 316
  • 317
  • 318
  • 319
  • 320
  • 321
  • 322
  • 323
  • 324
  • 325
  • ...

Ебукер (ebooker) – онлайн-библиотека на русском языке. Книги доступны онлайн, без утомительной регистрации. Огромный выбор и удобный дизайн, позволяющий читать без проблем. Добавляйте сайт в закладки! Все произведения загружаются пользователями: если считаете, что ваши авторские права нарушены – используйте форму обратной связи.

Полезные ссылки

  • Моя полка

Контакты

  • chitat.ebooker@gmail.com

Подпишитесь на рассылку: