Добавить в цитаты Настройки чтения

Страница 223 из 372

    Culture=neutral, PublicKeyToken=null

Notify

     <<<IN>>> parameters: {

msg= new Account operation: +5)

===SPbU.AOP_NET.Tax, MyServer, Version=0.0.0.0,

    Culture=neutral, PublicKeyToken=null

Notify

}

===SPbU.AOP_NET.Tax, MyServer, Version=0.0.0.0,

    Culture=neutral, PublicKeyToken=null

get_news

    <<<IN>>> parameters: {

}

===SPbU.AOP_NET.Tax, MyServer, Version=0.0.0.0,

   Culture=neutral, PublicKeyToken=null

get_news

    <<<OUT>>> parameters: {

}

===SPbU.AOP_NET.News, MyServer, Version=0.0.).0,

    Culture=neutral, PublicKeyToken=null

Notify

    <<<IN>>> parameters: {

msg= direct notification from Account)

===SPbU.AOP_NET.News, MyServer, Version=0.0.0.0,

    Culture=neutral, PublicKeyToken=null

Notify

    <<<OUT>>> parameters: {

}

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

Внесем в код сервера следующие дополнения:

namespace SPbU.AOP_NET {

……

public class Account: ContextBoundObject, IAccumulator,

      IAudit, IAccumulatorNew{

……

      public Account() {

……

           SynchronizationAttribute syncProperty =

               (SynchronizationAttribute)

                    Thread.CurrentContext.GetProperty {

                      "Synchronization");

            Console.WriteLine {

               "Account syncProperty == Tax syncProperty "+

               Object.ReferenceEquals(syncProperty, _tax.syncProperty));

       }

……

}

……

public class Tax: ContextBoundObject {

……

       private SynchronizationAttribute _syncProperty;

       public Tax() {

…….

             _syncProperty =

                  (SynchronizationAttribute)

                     Thread.CurrentContext.GetProperty {

                        "Synchronization");

……

       }

…….

       internal SynchronizationAttribute syncProperty {

            get { return _syncProperty;}

       }

……

}

…….

Просматривая консоль сервера убеждаемся, что ссылки на свойство синхронизации в обоих контекстах (в контексте, в котором живет компонент Account и в контексте, в котором живут компоненты Tax и News) указывают на один объект — свойство синхронизации домена синхронизации:

Server is listening

News context = 2 News constructor thread = 9 IsPoolThread = True

Tax context = 2 Tax constructor thread = 9 IsPoolThread = True

Account context = 1 Account constructor thread = 9 IsPoolThread = True





Account syncProperty == Tax syncProperty True

…….

Компоненты размещаются в трех контекстах и в двух доменах синхронизации

Заменим атрибут синхронизации, приписанный компоненту News следующей его версией:

[Synchronization(0x00000008)]

Задание данного атрибута означает, что компонент News будет располагаться в новом контексте (3), причем этот контекст образует и новый домен синхронизации. Компоненты Account и Tax должны располагаться в различных контекстах (1 и 2), но эти контексты должны входить в один домен синхронизации.

Для проверки этих утверждений внесем еще несколько дополнений в код сервера:

…….

namespace SPbU.AOP_NET {

……

      public class Tax: ContextBoundObject {

…….

            public Tax() {

…….

                Console.WriteLine {

                   "Tax syncProperty == News syncProperty "+

                  Object.ReferenceEquals(_syncProperty,

                     _news.syncProperty));

……

           }

…….

      }

…….

public class News: ContextBoundObject {

        private SynchronizationAttribute _syncProperty;

        public News() {

             _syncProperty =

                    (SynchronizationAttribute)

                        Thread.CurrentContext.GetProperty {

                               "Synchronization");

……

      }

……

      internal SynchronizationAttribute syncProperty {

             get { return _syncProperty;}

      }

…….

}

Просматривая консоль сервера убеждаемся в том, что компонент News размещается в новом домене синхронизации:

Server is listening

News context = 3 News constructor thread = 9 IsPoolThread = True

Tax syncProperty == News syncProperty False

Tax context = 2 Tax constructor thread = 9 IsPoolThread = True

Account context = 1 Account constructor thread = 9 IsPoolThread = True

Account syncProperty == Tax syncProperty True

…….

И последнее замечание касается файла LogFile. Просматривая его, можно заметить, что теперь перехватываются все вызовы, идущие к компонентам Tах и News, идущие не только от компонента Account, но и от компонента Tах к компоненту News. Это объясняется тем, что все компоненты живут в различных контекстах и все вызовы пересекают границу контекста и, следовательно, перехватываются.

Еще раз про атрибут синхронизации

Эта глава продолжает изучение кода атрибута синхронизации из Rotor, рассмотрение которого было начато в предыдущей главе. Там мы рассмотрели основные механизмы, связанные с определением контекста и домена синхронизации, в которых будет размещен новый объект — экземпляр класса, которому приписан атрибут SynchronizationAttribute. Это конструкторы (четыре варианта) и методы IsContextOK и GetPropertiesForNewContext класса SynchronizationAttribute. Теперь мы сосредоточимся на самом алгоритме синхронизации и попутно рассмотрим несколько важных понятий, связанных с программированием в CLR.

Инициализация свойства синхронизации в домене синхронизации

Начнем с метода InitIfNecessary класса SynchronizationAttribute:

internal virtual void InitlfNecessary() {

     lock(this) {

          if (_asyncWorkEvent == null) {

              _asyncWorkEvent = new AutoResetEvent(false);

              _workltemQueue = new Queue();

              _asyncLcidList = new ArrayList();

              WaitOrTimerCallback callBackDelegate =

                   new WaitOrTimerCallback(this.DispatcherCallBack);

              ThreadPool.RegisterWaitForSingleObject {

                 _asyncWorkEvent,

                 callBackDelegate,

                 null,

                 _timeOut,

                 false);

            }

     }

}

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