Читайте также:
|
|
Чтобы добавить в очередь пула потоков асинхронную вычислительную операцию, обычно вызывают один из следующих методов класса ThreadPool
static Boolean QueueUserWorkItem(WaitCallback callBack);
static Boolean QueueUserWorkItem(WaitCallback callBack, Object state);
static Boolean UnsafeQueueUserWorkItem(WaitCallback callBack, Object state);
Эти методы ставят рабочий элемент (вместе с дополнительными данными состояния) в очередь пула потоков и сразу возвращают управление приложению. Рабочий элемент — это просто указанный в параметре callback метод, который вызывается потоком из пула. Этому методу можно передать один параметр, указанный в параметре state (данные состояния). Версия метода QueueUserWorkltem без параметра state передаст null методу обратного вызова. В конце концов один из потоков пула обработает рабочий элемент, что приведет к вызову указанного метода. Создаваемый метод обратного вызова должен соответствовать типу-делегату System.ThreadingWaitCallback, который определяется так:
delegate void WaitCallback(Object state);
Метод UnsafeQueueUserWorkltem класса ThreadPool очень похож на чаще используемый метод QueueUserWorkItem. Вкратце скажу, чем они различаются. При обращении к ограниченному ресурсу (например, при открытии файла) CLR выполняет проверку доступа к коду (CAS), то есть наличие разрешений на доступ к ресурсу у всех сборок в стеке вызывающего потока. При отсутствии у какой-либо из них нужных разрешений CLR генерирует исключение SecurityException. В частности, это исключение возникнет, когда поток, выполняющий код сборки, у которой нет разрешения на открытие файла, все-таки попытается его открыть.
Чтобы обойти это ограничение, поток может поставить рабочий элемент в очередь пула потоков, тогда код открытия файла будет выполнен потоком из пула. Конечно, все это должно происходить в сборке, имеющей необходимые разрешения. Это «решение» обходит защиту и открывает злоумышленникам доступ к ресурсам с ограниченным доступом. Чтобы устранить эту брешь в защите, метод QueueUserWorkItem просматривает стек вызывающего потока и отслеживает все разрешения на доступ, а затем ассоциирует их с потоком из пула, когда он начинает выполняться. Таким образом, поток из пула работает теми же разрешениями, что и поток, вызвавший метод QueueUserWorkltem.
Просмотр стека потока и отслеживание всех разрешений на доступ заметно снижают производительность. Чтобы улучшить быстродействие постановки в очередь асинхронной вычислительной операции, можно вместо QueueUserWorkItem вызывать метод UnsafeQueueUserWorkltem, который просто ставит элемент в очередь к пулу потоков и не просматривает стек вызывающего потока. В результате этот метод выполняется быстрее, чем QueueUserWorkItem, но создает брешь в защите приложения. Поэтому UnsafeQueueUserWorkltem нужно вызывать, только будучи уверенным, что поток из пула будет выполнять код, не обращающийся к ресурсу с ограниченным доступом, или если обращение к этому ресурсу предусмотрено в приложении. Также учтите, что в коде, вызывающем метод UnsafeQueueUserWorkltem, должны быть установлены флаги ControlPolicy и ControlEvtdence для SecurityPermission — это не позволит ненадежному коду случайно или преднамеренно повысить уровень разрешений.
Асинхронные операции — это ключ к созданию высокопроизводительных, масштабируемых приложений, которые позволяют выполнять много операций, используя очень небольшое число потоков. А вкупе с пулом потоков они дают возможность эффективно задействовать все процессоры в системе. Осознавая этот огромный потенциал, группа разработчиков CLR приступила к созданию модели, которая сделала бы его доступным для всех программистов. Эта модель была названа моделью асинхронного программирования (АРМ).
Делегат можно вызвать на выполнение либо синхронно, как во всех приведенных ранее примерах, либо асинхронно с помощью методов BeginInvoke и EndInvoke. При вызове делегата с помощью метода BeginInvoke среда выполнения создает для исполнения метода отдельный поток и возвращает управление оператору, следующему за вызовом. При этом в исходном потоке можно продолжать вычисления.
Если при вызове BegiInvoke был указан метод обратного вызова, этот метод вызывается после завершения потока. Метод обратного вызова также задается с помощью делегата, при этом используется стандартный делегат AsyncCallback. В методе, обратного вызова для получения возвращаемого значения и выходных параметров применяется метод EndInvoke.
Если метод обратного вызова не был указан в параметрах метода BegiInvoke, метод EndInvoke можно использовать в потоке, инициировавшем запрос.
Класс Factorizer содержит метод Factorize, выполняющий разложение на множители. Этот метод асинхронно вызывается двумя способами: в методе Numl метод обратного вызова задается в BeginInvoke, в методе Num2 имеют место ожидание завершения потока и непосредственный вызов EndInvoke.
Дата добавления: 2015-01-30; просмотров: 76 | Поможем написать вашу работу | Нарушение авторских прав |