После создания экземпляра test класса Test вызывается его метод
NewEvent в результате чего из пула рабочих потоков извлекается новый поток, который и выполняет метод MyCallBack.
Напомним, что после этого событие
_myEvent автоматически переходит в начальное состояние.
Далее основной поток засыпает на 500 mc. В связи с тем, что интервал ожидания, заданный четвертым параметром в
ThreadPool.RegisterWaitForSingleObject равен 100 mc, метод MyCallBack будет вызван несколько раз по причине завершения
периода ожидания.
Далее во второй раз вызывается метод
NewEvent, и MyCallBack вызывается по причине перехода события _myEvent в состояние
signaled.
И, наконец, основной поток засыпает еще на 1000 mc, в течении которых
MyCallBack вызывается с интервалом 100 mc по
причине завершения времени ожидания.
Через 1000 mc основной поток просыпается и выполнение всего приложения (включая все рабочие потоки) завершается.
Ниже приводится вывод на консоль, полученный после запуска данного приложения:
>>> MyApp thread = 16 IsPoolThread = False
>>> Test constructor thread = 16 IsPoolThread = False
>>> MyCallback thread = 18 IsPoolThread = True
Test_1 : Count = 1 timedOut = False
>>> MyCallback thread = 18 IsPoolThread = True
Test_2 : Count = 2 timedOut = True
>>> MyCallback thread = 18 IsPoolThread = True
Test_3 : Count = 3 timedOut = True
>>> MyCallback thread = 18 IsPoolThread = True
Test_4 : Count = 4 timedOut = True
>>> MyCallback thread = 18 IsPoolThread = True
Test_5 : Count = 5 timedOut = True
>>> MyCallback thread = 18 IsPoolThread = True
Test_6 : Count = 6 timedOut = True
>>> MyCallback thread = 18 IsPoolThread = True
Test_7 : Count = 7 timedOut = False
>>> MyCallback thread = 18 IsPoolThread = True
Test_8 : Count = 8 timedOut = True
>>> MyCallback thread = 18 IsPoolThread = True
Test_9 : Count = 9 timedOut = True
>>> MyCallback thread = 18 IsPoolThread = True
Test_10 : Count = 10 timedOut = True
>>> MyCallback thread = 18 IsPoolThread = True
Test_11 : Count = 11 timedOut = True
>>> MyCallback thread = 18 IsPoolThread = True
Test_12 : Count = 12 timedOut = True
>>> MyCallback thread = 18 IsPoolThread = True
Test_13 : Count = 13 timedOut = True
>>> MyCallback thread = 18 IsPoolThread = True
Test_14 : Count = 14 timedOut = True
>>> MyCallback thread = 18 IsPoolThread = True
Test_15 : Count = 15 timedOut = True
>>> MyCallback thread = 18 IsPoolThread = True
Test_16 : Count = 16 timedOut = True
Возвращаемся к коду инициализации атрибута
Теперь можно более подробно обсудить код метода InitIfNecessary. Все тело этого метода включено в критическую секцию
lock(this) {}. Здесь this является ссылкой на экземпляр текущего класса
(
SynchronizationAttribute), который и является собственно свойством синхронизации (как контекста, так и домена
синхронизации). Таким образом, при входе текущего потока в данную критическую секцию никакой другой поток не может
войти в эту секцию (и в любую другую типа
lock(obj) {}, где obj является ссылкой на данное свойство синхронизации).
Далее проверяется условие
_asyncWorkEvent == null. Это условие выполняется только тогда, когда текущее свойство
синхронизации еще не инициализовано, т.е. в данный момент формируется новый домен синхронизации и текущее свойство
будет его свойством синхронизации. Именно в этом случае выполняется инициализация свойства. В противном случае код
инициализации пропускается, т.к. текущее свойство уже инициализированно ранее.
Инициализация состоит
из следующих шагов:
z Создается экземпляр _asyncWorkEvent события AutoResetEvent
Данное событие будет использовано для уведомления системы о том, что очередной рабочий поток из пула потоков может
выполнить очередной вызов, сохраненный в очереди вызовов (см. следующий пункт). Начальное состояние данного
события не равно signaled, и для уведомления системы это событие надо перевести в состояние signaled (после чего оно
автоматически вернется в исходное
состояние).
z Создается экземпляр _workItemQueue очереди Queue
Поддержание этой очереди - основная задача свойства синхронизации. Как правило, внешние вызовы, приходящие к
объектам некоторого домена синхронизации, преобразуются в специальную форму - так называемую работу, и сохраняются
в данной очереди (в некоторых случаях вызов не сохраняется в очереди и выполняется сразу же). Очередная работа
извлекается из этой очереди и выполняется при
готовности системы выполнять новую работу.
z Создается список _asyncLcidList
Данный список будет использоваться для хранения идентификаторов логических вызовов для асинхронных вызовов,
исходящих из данного домена синхронизации. Подробнее это будет обсуждаться далее.