Шрифт:
if (!IsNestedCall(work._reqMsg)) {……..
Правила обработки вложенного вызова зависят от реентерабельности контекста синхронизации. Если контекст реентерабельный, то никакой специальной обработки вложенных вызовов производить не надо. В этом случае любой новый вызов (в том числе и вложенный) имеет право исполняться в реентерабельном контексте в то время, как выполняемый в данный момент вызов приостановлен на время ожидания ответа на какой-либо сделанный в его рамках внешний вызов.
Если же контекст синхронизации нереентерабельный, то никакой новый вызов не может выполняться в данном контексте, если в данном контексте в данное время выполняется какой-либо синхронный вызов. Если при выполнении синхронного вызова была инициирована цепочка вызовов и последний в этой цепочке вызов является вызовом в данный контекст синхронизации, то его блокировка приведет к блокировке всей очереди вызовов (текущий вызов никогда не завершится). Именно в связи с этим в случае нереентерабельного контекста синхронизации и синхронного исполняемого вызова вложенный вызов должен исполняться вне очереди.
Рассмотрим определенный В ЭТОМ же классе SynchronizationAttribute метод IsNestedCall.
internal bool IsNestedCall(IMessage reqMsg) {
bool bNested = false;
if (!IsReEntrant) {
String lcid = SyncCallOutLCID;
if (lcid!= null) {
LogicalCallContext callCtx =
(LogicalCallContext)
reqMsg.Properties[Mes sage.CallContextKey];
if (callCtx!=null &&
lcid.Equals(callCtx.RemotingData.LogicalCalllD)) {
bNested = true;
}
}
if (IbNested && AsyncCallOutLCIDList.Count>0) {
LogicalCallContext callCtx =
(LogicalCallContext)
reqMsg.Properties[Message.CallContextKey];
if (AsyncCallOutLCIDList.Contains(
callCtx.RemotingData.LogicalCalllD)) {
bNested = true;
}
}
}
return bNested;
}
Этот метод возвращает true если текущий контекст (точнее, текущий домен синхронизации) нереентерабельный, а новый вызов (reqMsg) является вложенным для исполняемого в данный момент синхронного вызова, или для одного из исходящих асинхронных вызовов. Во всех остальных случаях возвращается false.
Вначале выясняется синхронность выполняемого в данный момент вызова:
String lcid = SyncCallOutLCID;
if (lcid!= null) {
......
}
Свойство SyncCallOutLCID атрибута синхронизации возвращает идентификатор логического вызова исполняемого в данный момент вызова, если этот вызов синхронный. В противном случае возвращается null.
Теперь в случае синхронности исполняемого вызова мы получаем доступ к контексту вызова для вызова reqMsg:
LogicalCallContext callCtx =
(LogicalCallContext)
reqMsg.Properties[Message.CallContextKey];
Надо заметить, что тут имеется ввиду класс Message из пространства имен System.Runtime.Remoting.Messaging. Реализация такого класса в этом пространстве имен имеется в Rotor, но отсутствует в .NET. Статическое поле CallContextKey равно __CallContext.
Если доступ к контексту вызова получен, то проверяется, что идентификатор логического вызова исполняемого в данный момент синхронного вызова lcid совпадает с идентификатором логического вызова для вызова reqMsg. В случае их совпадения флаг вложенности bNested получает значение true:
if (callCtx!=null &&
lcid.Equals(callCtx.RemotingData.LogicalCalllD)) {
bNested = true;
}
Здесь ОПЯТЬ приходится отметить, что в .NET у класса LogicalCallContext нет свойства RemotingData типа CallContextRemotingData, нет и самого класса CallContextRemotingData и его свойства LogicalCallID.
Если в данный момент не выполняется синхронный вызов, или новый вызов не является вложенным для исполняемого синхронного вызова, то начинается проверка вложенности нового вызова в один из исходящих асинхронных вызовов.
Выполнение условия 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