Шрифт:
Интервал:
Закладка:
Эксперименты
Эксперименты с вышеописанным кодом должны продемонстрировать работу сервисов синхронизации и трассировки вызовов.
Все компоненты размещаются в одном контексте
Первый эксперимент не требует какой-либо модификации кода клиента и сервера. Каждому компоненту (Account, Tax, News) приписаны два атрибута:
[Synchronization ()]
[MyCallTrace("LogFile")]
Таким образом, все три компонента требует одного и того же набора сервисов и их экземпляры размещаются в одном контексте.
Запустив серверное приложение и параллельно два клиентские приложения, мы увидим на консоли сервера информацию о том, что все три компонента выполняются в контексте 1.
Ниже приведены несколько первых строк с консоли сервера
Server is listening
News context = 1 News constructor thread = 3 IsPoolThread = True
Tax context = 1 Tax constructor thread = 3 IsPoolThread = True
Account context = 1 Account constructor thread = 3 IsPoolThread = True
Tax notification: new Account operation: +5
Tax Notify thread = 3 IsPoolThread = True
News notification: new Account operation: +5
News Notify thread = 3 IsPoolThread = True
News notification: direct notification from Account
News Notify thread = 3 IsPoolThread = True
Account Add thread = 3 IsPoolThread = True
Tax notification: new Account operation: +5
Tax Notify thread = 65 IsPoolThread = True
News notification: new Account operation: +5
News Notify thread = 65 IsPoolThread = True
News notification: direct notification from Account
News Notify thread = 65 IsPoolThread = True
Account Add thread = 65 IsPoolThread = True
Tax notification: new Account operation: +5
Tax Notify thread = 3 IsPoolThread = True
News notification: new Account operation: +5
News Notify thread = 3 IsPoolThread = True
News notification: direct notification from Account
News Notify thread = 3 IsPoolThread = True
Account Add thread = 3 IsPoolThread = True
…….
Еще одно замечание, связанное с консолью сервера — конструкторы компонентов выполняются в одном рабочем потоке, а далее эти компоненты вызываются двумя рабочими потоками. Эти потоки, конечно, никак не связаны с клиентами. Можно модифицировать код клиента и сервера, передавая при вызове метода Add не только сумму вклада, но и идентификатор процесса, в котором исполняется клиент, сделавший вызов. После этого можно заметить, что оба рабочих потока выполняют вызовы клиентов не зависимо от процесса клиента. Да и число рабочих потоков не связано напрямую с числом клиентов.
Модификация кода сервера (MyServer.cs) связана с добавлением интерфейса IAccumuiatorNew:
……
namespace SPbU.AOP_NET {
public interface IAccumuiatorNew{
void Add(int sum, int clientProcessId);
}
……
public class Account: ContextBoundObject, IAccumulator,
IAudit, IAccumuiatorNew!
……
public void Add(int sum, int clientProcessId){
_sum += sum;
_tax.Notify("new Account operation: +" + sum);
_tax.news.Notify("direct notification from Account");
Console.WriteLine("Account Add thread = " +
Thread.CurrentThread.GetHasheode() +
" IsPoolThread = " +
Thread.CurrentThread.IsThreadPoolThread +
" clientProcessId ="+ clientProcessId);
}
……
Необходимая модификация клиента (MуАрр. cs) представлена ниже
…….
using System.Diagnostics;
public class MyApp {
public static void Main() {
HttpChannel с = new HttpChannel();
ChannelServices.RegisterChannel(c);
Process p = Process.GetCurrentProcess();
try {
……
for (int i=0; i<100; i++) {
a. Add(5, p.Id);
}
…….
}
…….
Вот фрагмент вывода на консоль сервера из которого видно, что клиент никак не связан с рабочим потоком, выполняющим его вызов на сервере.
Account Add thread = 65 IsPoolThread = True clientProcessId =192
Tax notification: new Account operation: +5
Tax Notify thread = 65 IsPoolThread = True
News notification: new Account operation: +5
News Notify thread = 65 IsPoolThread = True
News notification: direct notification from Account
News Notify thread = 65 IsPoolThread = True
Account Add thread = 65 IsPoolThread = True clientProcessId =192
Tax notification: new Account operation: +5
Tax Notify thread = 3 IsPoolThread = True
News notification: new Account operation: +5
News Notify thread = 3 IsPoolThread = True
News notification: direct notification from Account
News Notify thread = 3 IsPoolThread = True
Account Add thread = 3 IsPoolThread = True clientProcessId =165
Tax notification: new Account operation: +5
Tax Notify thread = 3 IsPoolThread = True
News notification: new Account operation: +5
News Notify thread = 3 IsPoolThread = True
News notification: direct notification from Account
News Notify thread = 3 IsPoolThread = True
…….
Еще стоит обратить внимание на то, что рабочий поток, выполняющий вызов метода Add компонента Account, выполняет и вызовы метода Notify для компонентов Tах и News, инициированные из компонента Account. Причина в том, что в рамках данного эксперимента все три компонента находятся в одном контексте синхронизации, и поток, вошедший в этот контекст, не выходит из него, пока не будут сделаны все вышеупомянутые вызовы. Только после этого другой поток может войти в данный контекст и начать выполнение метода Add.
Просмотрев файл LogFile, в который выполняется запись данных о перехваченных вызовах, можно заметить, что трассируются только вызовы к компоненту Account. Это объясняется тем, что именно компонент Account получает вызовы извне контекста (от клиентов), и эти вызовы перехватываются перехватчиком входящих вызовов атрибута трассировки. Вызовы, которые делаются к компонентам Tах и News, идут от компонентов Account и Tах и не пересекают границу контекста. Именно поэтому они и не перехватываются. Первые строки файла LogFile представлены ниже:
===SPbU.AOP_NET.Account, MyServer, Version=0.0.0.0,
Culture=neutral, PublicKeyToken=null
ctor