Como já sabemos, a classe ThreadPool disponibiliza um repositório de threads que podemos utilizar em nossas aplicações, delegando a ela uma tarefa para ser executada através de um delegate. Para isso, é muito comum utilizarmos o método QueueUserWorkItem para enfileirar uma nova tarefa. O exemplo abaixo ilustra a sua utilização em uma aplicação qualquer:
ThreadPool.QueueUserWorkItem(state =>
{
Console.WriteLine(new StreamReader(@”C:TempArquivo.txt”).ReadToEnd());
});
Quando utilizamos o método QueueUserWorkItem, antes de enfileirar a tarefa a ser executada, ele captura todas as permissões que foram concedidas e, antes de executá-la, essas permissões são aplicadas a thread que está associada à tarefa. Com isso, se a tarefa que voce está tentando executar de forma assíncrona exigir alguma permissão e ela não foi concedida, uma exceção do tipo SecurityException será disparada. Podemos notar esse comportamento com o seguinte código:
new FileIOPermission(FileIOPermissionAccess.Read, @”C:TempArquivo.txt”).Deny();
ThreadPool.QueueUserWorkItem(state =>
{
Console.WriteLine(new StreamReader(@”C:TempArquivo.txt”).ReadToEnd());
});
No código acima, a aplicação não possui permissão de acesso ao arquivo, e ao executar o método QueueUserWorkItem, a tarefa vinculada também não conseguirá executar a leitura do arquivo, disparando uma exceção. Por menor que seja, utilizar este método sempre tem o overhead para a cópia das permissões atuais e associá-las a thread responsável pela tarefa, para que ela execute no mesmo contexto de segurança.
É justamente neste ponto que entra em cena o método UnsafeQueueUserWorkItem, também da classe ThreadPool. Ao contrário do método QueueUserWorkItem, ele não propaga as permissões para a worker thread, diminuindo o trabalho a ser realizado quando voce enfileira uma nova tarefa ao ThreadPool. A utilização em relação ao que vimos acima muda ligeiramente:
new FileIOPermission(FileIOPermissionAccess.Read, @”C:TempArquivo.txt”).Deny();
ThreadPool.UnsafeQueueUserWorkItem(state =>
{
Console.WriteLine(new StreamReader(@”C:TempArquivo.txt”).ReadToEnd());
}, null);
Como as permissões não são propagadas e avaliadas com o método UnsafeQueueUserWorkItem, mesmo que a aplicação não tenha as devidas permissões, a execução da tarefa ocorre sem maiores problemas.
É importante dizer aqui que a performance é melhorada mas, em contrapartida, a segurança fica vulnerável. Utilizar este tipo de código pode abrir portas para algum código malicioso, que pode utilizá-lo para elevar os privilégios de uma aplicação e, consequentemente, executar tarefas que atualmente ela não tem permissão. Opte sempre por utilizar esta técnica em uma tarefa em que voce não dependerá de nenhum recurso do sistema operacional (sistema de arquivos, registry, SQL Server, etc.), utilizando em conjunto com tarefas que dependam exclusivamente do processador, como é o caso de cálculos complexos, geração de algum conteúdo, etc., melhorando consideravelmente a performance na execução, sem abrir potenciais problemas de segurança.