Интернет-журнал "Домашняя лаборатория", 2007 №6
Шрифт:
MyDelegate hello = new MyDelegate(MyHello);
которому передается ссылка на метод MyHello этого же класса Test. Именно этот метод и формирует префикс вида Tеst_XXX:, где вместо XXX будет подставляться порядковый номер текущего вызова метода MyCallBack.
3. Порядковый номер вызова данного метода
При каждом вызове метода MyCallBack счетчик count увеличивается
4. Информация о причине вызова данного метода
Через параметр timedOut метод MyCallBack получает от системы информацию о причине его вызова. Если получено значение false, то этот метод был вызван благодаря тому, что кто-то установил событие myEvent в состояние signaled. Значение true будет получено в том случае, если метод был вызван по причине завершения срока ожидания.
Последний метод NewEvent класса Test как раз и может использоваться клиентами для перевода события _myEvent в состояние signaled.
Теперь вновь обратимся к коду метода Main.
После создания экземпляра test класса Test вызывается его метод NewEvent в результате чего из пула рабочих потоков извлекается новый поток, который и выполняет метод MyCallBack. Напомним, что после этого событие _myEvent автоматически переходит в начальное состояние.
Далее основной поток засыпает на 500 тс. В связи с тем, что интервал ожидания, заданный четвертым параметром в ThreadPool.RegisterWaitForSingleObject равен 100 mc, метод MyCallBack будет вызван несколько раз по причине завершения периода ожидания.
Далее во второй раз вызывается метод NewEvent, и MyCallBack вызывается по причине перехода события myEvent в состояние signaled.
И, наконец, основной поток засыпает еще на 1000 mс, в течении которых MyCallBack вызывается с интервалом 100 mс по причине завершения времени ожидания.
Через 1000 mс основной поток просыпается и выполнение всего приложения (включая все рабочие потоки) завершается.
Ниже приводится вывод на консоль, полученный после запуска данного приложения:
>>> МуАрр 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. Это условие выполняется только тогда, когда текущее свойство синхронизации еще не инициализовано, т. е. в данный момент формируется новый домен синхронизации и текущее свойство будет его свойством синхронизации. Именно в этом случае выполняется инициализация свойства. В противном случае код инициализации пропускается, т. к. текущее свойство уже инициализирование ранее.
Инициализация состоит из следующих шагов:
• Создается экземпляр _asyncWorkEvent события AutoResetEvent
Данное событие будет использовано для уведомления системы о том, что очередной рабочий поток из пула потоков может выполнить очередной вызов, сохраненный в очереди вызовов (см. следующий пункт). Начальное состояние данного события не равно signaled, и для уведомления системы это событие надо перевести в состояние signaled (после чего оно автоматически вернется в исходное состояние).