Segmentos e Threading
Sistemas operacionais utilizam processos para separar as diferentes aplicações que eles estão executando. Threads são a unidade básica à qual um sistema operacional aloca tempo do processador e mais de um thread pode estar executando código dentro desse processo. Cada thread mantém os manipuladores de exceção, uma prioridade de agendamento e um conjunto de estruturas que o sistema usa para salvar o contexto do thread até que ela está agendada. O contexto do thread inclui todas as as informações que o thread precisa para continuar perfeitamente a execução, incluindo o conjunto do segmento de registradores da CPU e pilha, no espaço de endereço do processo de host do thread.
A.NET Framework mais subdivide um processo do sistema operacional em leves subprocessos gerenciados, chamados de domínios de aplicativo, representados por System.AppDomain. Um ou mais threads gerenciados (representado por System.Threading.Thread) pode ser executado em um ou gerenciados de qualquer número de domínios de aplicativo dentro do mesmo processo. Embora cada domínio de aplicativo é iniciado com um único thread, o código desse domínio de aplicativo pode criar domínios de aplicativo adicional e segmentos adicionais. O resultado é que um segmento gerenciado pode se mover livremente entre domínios de aplicativo dentro do mesmo processo gerenciado; Você pode ter apenas um thread movendo entre vários domínios de aplicativo.
Um sistema operacional que ofereça suporte a multitarefa preemptiva cria o efeito de execução simultânea de vários segmentos de vários processos. Ele faz isso dividindo o tempo de processador disponíveis entre os threads que precisam dele, uma fatia de tempo do processador para cada segmento de alocar um após o outro. O thread atualmente em execução está suspenso quando o tempo decorrido da fatia e outro thread continua em execução. Quando o sistema alterna de um thread para outro, ele salva o contexto de segmento do segmento Admitiu Preempção e recarrega o contexto do thread salvo do próximo segmento na fila de thread.
O tamanho da fatia de tempo depende do sistema operacional e o processador. Como cada fatia de tempo é pequena, várias threads aparecem em execução ao mesmo tempo, mesmo se houver apenas um processador. Isso é realmente o caso em sistemas multiprocessadores, onde os threads executáveis são distribuídos entre os processadores disponíveis.
Quando usar vários segmentos
Software que requer interação do usuário deve reagir às atividades do usuário o mais rápido possível para fornecer uma experiência de usuário. Entretanto, ao mesmo tempo, ele deverá fazer os cálculos necessários para apresentar dados ao usuário o mais rápido possível. Se o seu aplicativo usa apenas um thread de execução, você pode combinar programação assíncrona com .NET Framework remoting ou Serviços XML da Web criados usando ASP.NET para usar o tempo de processamento de outros computadores além do seu próprio para aumentar a capacidade de resposta para o usuário e diminuir o tempo de processamento de dados do seu aplicativo. Se você estiver fazendo o trabalho intenso de entrada/saída, você também pode usar as portas de conclusão de e/S para aumentar a capacidade de resposta do aplicativo.
Vantagens de vários segmentos
No entanto, usando mais de um segmento, é a técnica mais poderosa disponível para aumentar a capacidade de resposta para o usuário e processar os dados necessários para realizar o trabalho quase ao mesmo tempo. Em um computador com um processador, vários threads podem criar esse efeito, tirando proveito dos pequenos períodos de tempo entre eventos de usuário para processar os dados em segundo plano. Por exemplo, um usuário pode editar uma planilha, enquanto outro thread é recalculando a outras partes da planilha dentro do mesmo aplicativo.
Sem modificação, o mesmo aplicativo seria aumentar drasticamente a satisfação do usuário quando executado em um computador com mais de um processador. Seu único domínio de aplicativo pode usar vários segmentos para realizar as seguintes tarefas:
Se comunicam através de uma rede, em um servidor Web e um banco de dados.
Execute operações que levam a uma grande quantidade de tempo.
Distingui as tarefas de prioridade variada. Por exemplo, um segmento de alta prioridade gerencia tarefas críticas de tempo e um thread de baixa prioridade executa outras tarefas.
Permitir que a interface do usuário permaneça responsivo, ao alocar tempo para tarefas em segundo plano.
Desvantagens de vários segmentos
É recomendável que você use como poucos segmentos quanto possível, minimizando assim o uso dos recursos do sistema operacional e melhorando o desempenho. Threading também tem requisitos de recursos e possíveis conflitos a serem considerados ao projetar seu aplicativo. Os requisitos de recursos são:
O sistema consome memória as informações de contexto, exigidas por processos, AppDomain objetos e threads. Portanto, o número de processos, AppDomain objetos e segmentos que podem ser criados é limitado pela memória disponível.
Manter o controle de um grande número de threads consome muito tempo do processador. Se houver muitos segmentos, a maioria deles não fará um progresso significativo. Se a maioria dos threads atuais estiver em um processo, os threads em outros processos são agendadas com menos freqüência.
Controlando a execução de código com vários segmentos é complexo e pode ser uma fonte de vários bugs.
Destruição de segmentos exige saber o que poderia acontecer e lidar com essas questões.
Fornecer acesso compartilhado a recursos pode criar conflitos. Para evitar conflitos, sincronizar ou controlar o acesso a recursos compartilhados. Falha ao sincronizar o acesso corretamente (em domínios de aplicativo iguais ou diferentes) pode levar a problemas como, por exemplo, deadlocks (no quais dois threads parar de responder enquanto cada um aguarda o outro Concluir) e as condições de corrida (quando um resultado anormais ocorre devido a uma dependência crítica inesperada a temporização dos dois eventos). O sistema fornece os objetos de sincronização que podem ser usados para coordenar o recurso de compartilhamento entre vários threads. Reduzindo o número de threads se torna mais fácil sincronizar os recursos.
Os recursos que exigem sincronização:
Recursos do sistema (como portas de comunicação).
Recursos compartilhados por vários processos (como identificadores de arquivo).
Os recursos de um único domínio de aplicativo (como, por exemplo, global, static e campos de instância) acessado por vários segmentos.
Design de Threading e de aplicativo
Em geral, usando o ThreadPool classe é a maneira mais fácil lidar com vários segmentos para tarefas relativamente curtos que não impedirá que outros threads e quando você não espera agendamento específico de tarefas. No entanto, há inúmeras razões para criar seus próprios segmentos:
Se você precisar de uma tarefa para ter uma prioridade particular.
Se você tiver uma tarefa que pode ser um longo tempo de execução (e, portanto, bloquear outras tarefas).
Se você precisa colocar a threads em um single-threaded apartment (todos os ThreadPool segmentos estão na multithreaded apartment).
Se você precisar de uma associado ao segmento de identidade estável. Por exemplo, você deve usar um thread dedicado a anulação de thread, suspendê-lo ou descobrir a ele pelo nome.
Se você precisar executar threads em segundo plano que interagem com a interface do usuário, o.NET Framework versão 2.0 fornece um BackgroundWorker componente que se comunica usando eventos, com o empacotamento de thread cruzado para o segmento de interface do usuário.
Threading e exceções
Tratar exceções em segmentos. Em geral, exceções sem tratamento em threads, até mesmo plano de fundo de threads, terminar o processo. Há três exceções a essa regra:
A ThreadAbortException é lançada em um thread porque Abort foi chamado.
Um AppDomainUnloadedException é lançada em um thread porque o domínio do aplicativo está sendo descarregado.
O common language runtime ou um processo de host encerra o thread.
Para obter mais informações, consulte Exceções de Threads gerenciados.
Observação
No.NET Framework versões 1.0 e 1.1, o common language runtime silenciosamente intercepta algumas exceções, por exemplo, em threads do pool.Isso pode corromper o estado do aplicativo e eventualmente causar aplicativos travar, que podem ser muito difícil de depurar.