`
Читать книги » Книги » Разная литература » Газеты и журналы » Интернет-журнал "Домашняя лаборатория", 2007 №6 - Усманов

Интернет-журнал "Домашняя лаборатория", 2007 №6 - Усманов

Перейти на страницу:

      lock(_workltemQueue) {

             _workItemQueue.Dequeue();

       }

}

Иными словами, фиктивная работа просто удаляется из очереди, после чего выполнение метода SyncProcessMessage завершается возвращением результата replyMsg и разбуженный поток продолжает выполнять основной вызов.

Случай нереентерабельного контекста

Теперь рассмотрим ветвь метода SyncProcessMessage класса SynchronizedClientContextSink, относящуюся к случаю нереентерабельного контекста:

public virtual IMessage SyncProcessMessage (

       IMessage reqMsg) {

       IMessage replyMsg;

       if (_property.IsReEntrant) {

             ……

        }

        else {

             LogicalCallContext cctx =

                (LogicalCallContext)

                    reqMsg.Properties[Message.CallContextKey];

              String lcid = cctx.RemotingData.LogicalCalllD;

              bool bClear = false;

              if (lcid == null) {

                  lcid = Identity.GetNewLogicalCalllD ();

                  cctx.RemotingData.LogicalCalllD = lcid;

                  bClear = true;

              }

              bool bTopLevel=false;

              if (_property.SyncCallOutLCID==null) {

                  _property.SyncCallOutLCID = lcid;

                  bTopLevel = true;

               }

               replyMsg = _nextSink.SyncProcessMessage(reqMsg);

               if (bTopLevel) {

                   _property.SyncCallOutLCID = null;

                   if (bClear) {

                        LogicalCallContext cctxRet =

                               (LogicalCallContext)

                                      replyMsg.Properties[Message.CallContextKey];

                        cctxRet.RemotingData.LogicalCalllD = null;

                          }

                   }

         }

           return replyMsg;

}

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

Прежде всего нужно узнать идентификатор исходящего вызова. Для этого получаем доступ к его контексту вызова

LogicalCallContext cctx =

     (LogicalCallContext)

              reqMsg.Properties[Message.CallContextKey];

и, затем, к самому идентификатору

String lcid = cctx.RemotingData.LogicalCallID;

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

bool bClear = false;

if (lcid == null) {

    lcid = Identity.GetNewLogicalCalllD();

    cctx.RemotingData.LogicalCalllD = lcid;

    bClear = true;

}

Здесь статический метод GetNewLogicalCallID класса Identity генерирует новый идентификатор, который и запоминается в контексте вызова.

Если нам пришлось самим построить новый идентификатор для исходящего синхронного вызова, то его нужно и сохранить в свойстве синхронизации. В этом случае условное выражение в следующем операторе if равно true:

bool bTopLevel=false;

if (_property.SyncCallOutLCID==null) {

     _property.SyncCallOutLCID = lcid;

     bTopLevel = true;

}

Ну а теперь передаем исходящий вызов следующему перехватчику исходящих вызовов и ждем ответа

replyMsg = _nextSink.SyncProcessMessage(reqMsg);

Ну а теперь (после получения ответа) надо за собой почистить (если мы что-то поменяли в контексте вызова и в свойстве синхронизации):

if (bTopLevel) {

    _property.SyncCallOutLCID = null;

    if (bClear) {

         LogicalCallContext cctxRet =

              (LogicalCallContext)

                    replyMsg.Properties[Message.CallContextKey];

         cctxRet.RemotingData.LogicalCalllD = null;

      }

}

Здесь мы обнуляем свойство SyncCallOutLCID свойства синхронизации (если мы его только что сами установили) и обнуляем идентификатор для полученного ответа replyMsg (если мы сами задавали этот идентификатор для исходящего вызова).

Перехват исходящих асинхронных вызовов

Для обработки исходящих асинхронных вызовов перехватчик использует следующий код:

public virtual IMessageCtrl AsyncProcessMessage(

      IMessage reqMsg,

      IMessageSink replySink) {

      IMessageCtrl msgCtrl = null;

      if (!_property.IsReEntrant) {

          LogicalCallContext cctx =

                (LogicalCallContext)

                      reqMsg.Properties[Message.CallContextKey];

           String lcid = Identity.GetNewLogicalCalllD();

           cctx.RemotingData.LogicalCalllD = lcid;

           _property.AsyncCallOutLCIDList.Add(lcid);

       }

       AsyncReplySink mySink =

            new AsyncReplySink(replySink, _property);

        msgCtrl = _nextSink.AsyncProcessMessage (

                           reqMsg,

                           (IMessageSink)mySink);

       return msgCtrl;

}

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

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

if (!_property.IsReEntrant) {

     LogicalCallContext cctx =

           (LogicalCallContext)

                 reqMsg.Properties[Message.CallContextKey];

      String lcid = Identity.GetNewLogicalCallID();

      cctx.RemotingData.LogicalCalllD = lcid;

      _property.AsynCallOutLCIDList.Add(lcid);

}

Зачем вообще сохраняется список идентификаторов исходящих асинхронных вызовов? И почему он обновляется только для нереентерабельного случая?

Единственно, для чего этот список необходим (и именно в случае нереентерабельного контекста) — для определения того, является ли новый входящий вызов вложенным (см. код методов IsNestedCall и HandleWorkRequest). При изложении этого вопроса ранее уже отмечалось наличие некоторых проблем, связанных с определение понятия вложенного вызова и его использования.

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

AsyncReplySink mySink =

         new AsyncReplySink(replySink, _property);

Класс AsyncReplySink будет рассмотрен чуть позже.

И вот, наконец, исходящий асинхронный вызов reqMsg передается следующему перехватчику исходящих асинхронных вызовов, а для получения уведомления указывается mySink:

msgCtrl = _nextSink.AsyncProcessMessage (

                     reqMsg,

                     (IMessageSink)mySink);

return msgCtrl;

Теперь рассмотрим класс AsyncReplySink:

internal class AsyncReplySink: IMessageSink {

…..

}

В конструкторе

Перейти на страницу:

Откройте для себя мир чтения на siteknig.com - месте, где каждая книга оживает прямо в браузере. Здесь вас уже ждёт произведение Интернет-журнал "Домашняя лаборатория", 2007 №6 - Усманов, относящееся к жанру Газеты и журналы / Сделай сам / Хобби и ремесла. Никаких регистраций, никаких преград - только вы и история, доступная в полном формате. Наш литературный портал создан для тех, кто любит комфорт: хотите читать с телефона - пожалуйста; предпочитаете ноутбук - идеально! Все книги открываются моментально и представлены полностью, без сокращений и скрытых страниц. Каталог жанров поможет вам быстро найти что-то по настроению: увлекательный роман, динамичное фэнтези, глубокую классику или лёгкое чтение перед сном. Мы ежедневно расширяем библиотеку, добавляя новые произведения, чтобы вам всегда было что открыть "на потом". Сегодня на siteknig.com доступно более 200000 книг - и каждая готова стать вашей новой любимой. Просто выбирайте, открывайте и наслаждайтесь чтением там, где вам удобно.

Комментарии (0)