Чтение онлайн

на главную - закладки

Жанры

Интернет-журнал "Домашняя лаборатория", 2007 №6
Шрифт:

Выполнение условия AsyncCallOutLCIDList.count>0 означает, что список идентификаторов логических вызовов, соответствующих исходящим асинхронным вызовам, не пуст. Свойство AsyncCallOutLCIDList типа ArrayList возвращает ссылку на этот список.

В этом случае как и ранее выясняется контекст вызова reqMsg и проверяется, что соответствующий ему идентификатор логического вызова содержится в списке исходящих асинхронных вызовов. В случае успеха флаг bNested

получает значение true:

LogicalCallContext callCtx =

(LogicalCallContext)

reqMsg.Properties[Message.CallContextKey];

if (AsyncCallOutLCIDList.Contains(

callCtx.RemotingData.LogicalCalllD)) {

bNested = true;

}

Возвращаемся вновь к коду метода HandleWorkRequest, который мы рассматриваем в данный момент только для случая инкапсулированного синхронного вызова.

Здесь возможны два случая:

IsNestedCall(work._reqMsg) == false

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

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

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;

}

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

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

Шведский стол

Ланцов Михаил Алексеевич
3. Сын Петра
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Шведский стол

Дворянская кровь

Седой Василий
1. Дворянская кровь
Фантастика:
попаданцы
альтернативная история
7.00
рейтинг книги
Дворянская кровь

Краш-тест для майора

Рам Янка
3. Серьёзные мальчики в форме
Любовные романы:
современные любовные романы
эро литература
6.25
рейтинг книги
Краш-тест для майора

Любовь Носорога

Зайцева Мария
Любовные романы:
современные любовные романы
9.11
рейтинг книги
Любовь Носорога

Темный Лекарь 5

Токсик Саша
5. Темный Лекарь
Фантастика:
фэнтези
аниме
5.00
рейтинг книги
Темный Лекарь 5

Печать Пожирателя

Соломенный Илья
1. Пожиратель
Фантастика:
попаданцы
аниме
сказочная фантастика
фэнтези
5.00
рейтинг книги
Печать Пожирателя

Враг из прошлого тысячелетия

Еслер Андрей
4. Соприкосновение миров
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Враг из прошлого тысячелетия

Начальник милиции. Книга 5

Дамиров Рафаэль
5. Начальник милиции
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Начальник милиции. Книга 5

Возвышение Меркурия. Книга 16

Кронос Александр
16. Меркурий
Фантастика:
попаданцы
аниме
5.00
рейтинг книги
Возвышение Меркурия. Книга 16

Метатель

Тарасов Ник
1. Метатель
Фантастика:
боевая фантастика
попаданцы
рпг
фэнтези
фантастика: прочее
постапокалипсис
5.00
рейтинг книги
Метатель

Запрети любить

Джейн Анна
1. Навсегда в моем сердце
Любовные романы:
современные любовные романы
5.00
рейтинг книги
Запрети любить

На Ларэде

Кронос Александр
3. Лэрн
Фантастика:
фэнтези
героическая фантастика
стимпанк
5.00
рейтинг книги
На Ларэде

Третий. Том 4

INDIGO
Вселенная EVE Online
Фантастика:
боевая фантастика
космическая фантастика
попаданцы
5.00
рейтинг книги
Третий. Том 4

Сочинения в трех томах. Том 1

Леблан Морис
Большая библиотека приключений и научной фантастики
Детективы:
классические детективы
5.00
рейтинг книги
Сочинения в трех томах. Том 1