Escalonamento no Windows

2.827 visualizações

Publicada em

Disciplina: Sistemas Operacionais
Curso: Sistemas de Informação
Assunto: Escalonamento no Windows

Publicada em: Tecnologia
0 comentários
1 gostou
Estatísticas
Notas
  • Seja o primeiro a comentar

Sem downloads
Visualizações
Visualizações totais
2.827
No SlideShare
0
A partir de incorporações
0
Número de incorporações
3
Ações
Compartilhamentos
0
Downloads
94
Comentários
0
Gostaram
1
Incorporações 0
Nenhuma incorporação

Nenhuma nota no slide

Escalonamento no Windows

  1. 1. ESCALONAMENTO no Alunos: Felipe de Souza da Costa Fernanda Gomes Giselle Nascimento Nildo Wilpert
  2. 2. Tópicos • Visão geral • Definição do escalonador • Níveis de prioridade • Aumento de prioridade • Postergação indefinida • Threads de tempo real • Estados de uma thread • Troca de contexto • Cenários de escalonamento • Threads Idle • Sistemas multiprocessador • Afinidade
  3. 3. Visão geral • O Windows implementa um escalonador do tipo Multilevel Feedback Queue. • Certas threads executam sempre (threads de mais alta prioridade). • Por padrão, a thread pode ser executada por qualquer processador dentro de um grupo de processadores na qual a thread está previamente associada (normalmente um grupo de até 64 processadores). Porém desenvolvedores podem alterar a afinidade utilizando API’s adequadas, enquanto que os usuários podem utilizar ferramentas para alterá-la em tempo de execução. (gerenciador de tarefas). • O desenvolvedor pode também optar por criar aplicações que suportam mais de um grupo de processadores, utilizando API’s extendidas para associar a afinidade da thread a processadores lógicos de diferentes grupos, passando este a ser um processo multi-grupo, que teoricamente, pode ser executado por qualquer processador disponível dentro da máquina.
  4. 4. Visão geral • Depois que a thread é selecionada, ela passa a ser executada por um tempo determinado (quantum). • Quantum é um período de tempo que uma thread pode ser executada antes que outra thread ao mesmo nível de prioridade passe a ser executada. • Valores de quantum podem variar de sistema para sistema e de processo para processo por qualquer uma das três razões: • Pelas definições do sistema (quantum longo ou curto, quantum variável ou fixo e filas de prioridades) • Uso de primeiro e segundo plano para um processo • Por uma alteração do quantum, causada por uma chamada de sistema.
  5. 5. Visão geral • Uma thread pode não completar seu quantum, pois como vimos, o Windows implementa um escalonamento Multilevel Feedback Queue, ou seja, se outra thread com uma prioridade mais alta torna-se pronta para ser executada, a thread em execução é interrompida (preemptada) antes de completar sua fatia de tempo.
  6. 6. Definição do Escalonador • A estrutura do kernel do Windows é híbrida. • Neste modelo de kernel, os seus componentes principais ( Escalonadores, IPC base) continuam sendo mantidos no modo kernel apenas. • Porém sendo híbrido, ele tem a capacidade de agregar ou desagregar funcionalidades, sem perder performance ou estabilidade presentes na sua estrutura inicial, através dos módulos chamados “servidores”
  7. 7. Definição do Escalonador • O código do Escalonador do Windows é implementado no kernel. • Não há um único módulo ou rotina de escalonamento, pois o código é espalhado por todo o kernel. • A rotina que desempenha essas tarefas é chamada de Despachador do kernel.
  8. 8. Definição do Escalonador • Os seguintes eventos podem chamar o Despachador: • Uma thread fica pronta para executar, por exemplo, uma thread que acabou de ser criada ou que acabou de sair do estado de Espera. • Uma thread sai do estado de Execução pois o seu quantum acabou ou quando entra no estado de Espera. • A prioridade de uma thread muda, ou devido a uma chamada de sistema ou porque o próprio Windows muda a sua prioridade. • Quando a Afinidade do processador em que a thread está executando muda, fazendo com que a thread não possa mais ser executada naquele núcleo.
  9. 9. Definição do Escalonador • Para cada um desses eventos, o Windows deve determinar qual thread deve executar em seguida. • O escalonador mantém uma fila de threads executáveis para cada nível de prioridade. • Quando o processador se torna disponível, o sistema realiza a troca de contexto.
  10. 10. Definição do Escalonador • Como foi visto, o Windows escalona usando as threads. • Essa abordagem faz sentido quando se considera que os processos não executam, mas apenas fornecem recursos e um contexto para a execução das suas threads. • Como as decisões do Escalonador são baseadas estritamente nas threads, nenhuma consideração é dada ao processo a qual a thread pertence. • Por exemplo, se um processo A tiver 10 threads executáveis, um Processo B tiver 2 threads executáveis, e todas as 12 threads estiverem na mesma prioridade, cada thread teoricamente receberia 1/12 do tempo da CPU (Windows não daria 50% do tempo da CPU para o processo A e 50% para o processo B).
  11. 11. Níveis de prioridade • O Windows usa 32 níveis de prioridade, variando de 0 a 31, sendo dividido em: • Dezesseis níveis de prioridade de tempo real. (16º nível ao 31º nível) • Dezesseis níveis de prioridade variável. (nível 0 ao 15º nível) • A thread 0 (zero-page) pode ter a prioridade zero. A thread "zero-page" é uma thread do sistema responsável por zerar quaisquer "páginas livres" quando não há outras threads para executar.
  12. 12. Níveis de prioridade das Threads • Os níveis de prioridade são atribuídos a partir de duas perspectivas diferentes: API do Windows e Kernel do Windows.
  13. 13. API do Windows 1- Organiza os processos em seis classes de prioridades: BASE SetPriorityClass TEMPO REAL 24 REALTIME_PRIORITY_CLASS ALTA 13 HIGH_PRIORITY_CLASS ACIMA DO NORMAL 10 ABOVE_NORMAL_PRIORITY_CLASS NORMAL 8 NORMAL_PRIORITY_CLASS ABAIXO DO NORMAL 6 BELLOW_PRIORITY_CLASS BAIXA/ESPERA 4 IDLE_PRIORITY_CLASS
  14. 14. API do Windows 2- Atribui uma prioridade relativa a cada thread dentro do processo a qual a mesma pertence. valor SetThreadPriority Inativa -15 THREAD_PRIORITY_IDLE Mais baixa -2 THREAD_PRIORITY_LOWEST Abaixo do normal -1 THREAD_PRIORITY_BELOW_NORMAL Normal 0 THREAD_PRIORITY_NORMAL Acima do normal 1 THREAD_PRIORITY_ABOVE_NORMAL Mais alta 2 THREAD_PRIORITY_HIGHEST Tempo critico 15 THREAD_PRIORITY_TIME_CRITICAL
  15. 15. Kernel do Windows • A prioridade relativa da thread é então aplicada como uma diferença entre a prioridade base do processo e a prioridade relativa da thread. • Por exemplo: A thread com prioridade “mais alta” (THREAD_PRIORITY_HIGHEST) receberá a prioridade base da sua classe de processo, neste caso 10, supondo ABOVE_NORMAL_PRIORITY_CLASS, a prioridade relativa da thread seria 12. • Considerando que o processo tem apenas um único valor de prioridade base, cada thread tem dois valores de prioridade: corrente e base. • Decisões de escalonamento são feitas com base na prioridade atual.
  16. 16. Prioridade base do processo • Normalmente, em aplicações usuário, a prioridade do processo é a NORMAL_PRIORITY_CLASS (Prioridade 8). • No entanto isso pode ser alterado.
  17. 17. Aumento de prioridade • O escalonador do Windows ajusta periodicamente a prioridade atual das threads do nível variável através de um mecanismo de aumento de prioridade interna. • Em muitos casos, ele faz isso para diminuir várias latências e aumentar a capacidade de resposta mais justa quanto possível. • Em outros, aplica esses impulsos para evitar cenários de postergação indefinida.
  18. 18. Aumento de prioridade • O aumento de prioridade pode ser causado por: • Evento expedido pelo escalonador/despachador; • Quando uma operação de entrada e saída é completada; • Depois de uma thread em primeiro plano completar o estado de espera; • Uma GUI thread (Graphical User Interfaces) é chamada devido a algum evento de janela, como por exemplo, apertar um botão para cancelar; • Quando uma thread que está pronta para executar está esperando por muito tempo (postergação indefinida);
  19. 19. Aumento de prioridade • A intenção desses ajustes é tentar prover uma capacidade de resposta mais justa possível nos cenários de escalonamento, mas como qualquer algoritmo de escalonamento, estes ajustes não são perfeitos e nem sempre beneficia todas as aplicações. • Vale ressaltar que o Windows nunca ajusta a prioridade de threads do nível de tempo real (16 a 31), para que elas sempre tenham a mesma base e prioridade atual.
  20. 20. Postergação indefinida • Imagine a seguinte situação: • Tem-se uma thread de prioridade 7 que está em execução, impedindo uma thread de prioridade 4 de receber tempo da CPU; • Entretanto, uma thread de prioridade 11 está esperando por algum recurso que a thread de prioridade 4 bloqueou. • Mas como a thread de prioridade 7 está tomando todo o tempo da CPU, a thread de prioridade 4 nunca irá executar por tempo suficiente para terminar o que quer que ela esteja fazendo e disponibilizar o recurso que bloqueia a thread de prioridade 11. • Como o Windows lida com essa situação?
  21. 21. Postergação indefinida • Uma vez por segundo, o "Gerenciador de Equilíbrio" (Balance Set Manager), uma thread de sistema que existe principalmente para realizar funções de gerenciamento de memória, procura filas prontas de quaisquer threads que estiveram em estado de "pronto" (isto é, que não executaram ainda) por 4 segundos. • Se ele encontrar essa thread, o Gerenciador de Equilíbrio aumenta a prioridade da thread para 15. • Nos Windows 2000 e XP o quantum da thread é alterado para duas vezes o quantum do processo. • No Windows Server 2003, o quantum é alterado para 4 unidades. • Uma vez que o quantum acabou, a prioridade é imediatamente reduzida para sua prioridade base original. Se a thread não houver terminado e uma thread de prioridade maior estiver pronta para executar, a thread que foi reduzida volta para a fila "pronta", onde, novamente, esta fica disponível para um novo aumento se ficar lá (na fila) por mais 4 segundos.
  22. 22. Postergação indefinida • O Gerenciador de Equilíbrio não verifica realmente todas as threads sempre que é executado. • Para minimizar o tempo de CPU utilizado, ele verifica somente 16 threads prontas; se houver mais threads naquele nível de prioridade, ele se lembra onde parou e inicia o próximo passo. • Além disso, ele aumentará apenas dez threads em cada passagem - se ele encontrar dez threads que mereçam esse aumento, ele para a verificação naquele ponto e inicia na próxima passagem.
  23. 23. Postergação indefinida • Este algoritmo sempre conseguirá resolver o problema da postergação indefinida? • Não - ele não é perfeito de forma alguma. Mas ao longo do tempo, threads sedentas (starved) pela CPU vão conseguir tempo suficiente para terminar o que estiverem fazendo e voltar ao estado de espera.
  24. 24. Processo de tempo real • Muitos processos do sistema no modo kernel, como aqueles que gerenciam as operações de I/O, executam na classe de prioridade de tempo real. • Os sistemas em tempo real têm tempos de resposta previsíveis. Os resultados são bem sucedidos se forem precisos e oportunos. O tempo de resposta nem sempre tem que ser rápido. Um sistema é em “tempo real” quando as atividades de processamento têm prazos. • Um sistema de tempo real "hard" é aquele em que a falha em atender um prazo indica uma falha total do sistema. • Com o tempo real "soft", perder um prazo indica que o sistema não está funcionando em seu pico. • Os sistemas em tempo real geralmente são reativos, o que significa que se comportam com base nas condições do ambiente.
  25. 25. Processo de tempo real Observação • Ao aumentar a prioridade para o intervalo de tempo real, esteja ciente que muitas threads importantes estão executando nesse intervalo, caso essa thread fiquem muito tempo executando isso pode bloquear funções críticas do sistema. • Usando as APIs padrão do Windows , uma vez que um processo tenha entrado no intervalo em tempo real, todas suas threads (mesmo os de repouso) devem ser executadas em um dos níveis de prioridade de tempo real.
  26. 26. Threads idle • „Existe ainda uma classe especial chamada idle (IDLE_PRIORITY_CLASS) a de mais baixa prioridade. Threads nesta classe somente executam quando não existem outras threads aptas (portanto, threads dessa classe não interferem na performance –não causam overhead).
  27. 27. Estados da thread No Windows XP: 1. Inicializado: É o momento em que o processo é iniciado para que possa ser executado pelo processador 2. Pronto: Uma vez criada, a thread aguarda para usar o processador no estado Pronto 3. Reserva: A thread entra no estado reserva quando é decidido em qual processador será executada, aguardando por sua vez 4. Execução: Uma vez obtido o processador, a thread entra em estado de execução. Ela irá sair desse estado quando: 1. Acabar o seu Quantum 2. Término da execução 3. Preempção (quando aparece outra de maior prioridade) 4. For suspenso 5. Estiver esperando um objeto
  28. 28. Estados da thread 5. Terminado: Quando a Thread terminou de executar 6. Espera: Quando a thread necessita de uma entrada ou saída 7. Transição: Quando a thread concluir sua espera, ou ela volta para o estado pronto ou entra no estado de transição. A pilha de núcleo de uma thread no estado de transição foi paginada para fora da memória (por exemplo, porque não executou por um período de tempo e o sistema precisou de memória para outros propósitos), mas, para todos os efeitos, a thread está pronta para executar. 8. Desconhecido: Quando o sistema não está seguro do estado da Thread (usualmente devido a um erro).
  29. 29. Estados da thread
  30. 30. Estados da thread • A criação de um processo em Windows 2000 corresponde a instanciar(criar) um objeto do tipo processo, o qual é uma espécie de “molde” para novos processos. • Nesse momento, uma série de atributos são inicializados para esse novo processo, como, por exemplo, um identificador de processo (pid), descritores de proteção, prioridades, etc. • A unidade de escalonamento do Windows 2000 é o conceito de thread. A cada processo está associada pelo menos uma thread. • Cada thread pode criar outras threads. Essa organização permite a execução concorrente dos processos, além de possibilitar uma concorrência entre as threads que pertencem a um mesmo processo. • A thread pode estar em um dos seis estados:
  31. 31. Estados da thread
  32. 32. Troca de contexto • Uma troca de contexto (também conhecido como chaveamento) é o processo computacional capaz de armazenar e restaurar o estado (contexto) de uma CPU de forma que múltiplos processos possam compartilhar uma única instância de CPU. • É garantido que quando o contexto anterior armazenado seja restaurado, o ponto de execução volte ao mesmo estado que foi deixado durante o armazenamento.
  33. 33. Troca de contexto • O escalonador mantém uma fila de threads executáveis para cada nível de prioridade. Estas são chamadas ready threads (threads prontas). Quando o processador se torna disponível, o sistema realiza a troca de contexto. Os passos da troca de contexto são: • 1- Salvar o contexto da thread que acabou de ser executada • 2- Colocar a thread que acabou de terminar sua execução no final da fila de prioridade • 3- Encontrar a fila de maior prioridade que contém ready threads • 4- Retirar a thread no início da fila, carregar seu contexto e executá-la
  34. 34. Troca de contexto Threads que não entram na lista de prontos: • Threads criadas com a flag CREATE_SUSPENDED - A thread é criada em um estado “suspenso” e não executa até que a função ResumeThread seja chamada. • Threads interrompidas durante a execução com função SuspendThread ou SwitchToThread • Threads esperando por um objeto de sincronização ou de entrada. Enquanto threads que estão suspensas ou bloqueadas não ficam prontas para rodar, o escalonador não aloca nenhum tempo de processo a elas.
  35. 35. Troca de contexto As razões mais comuns para troca de contexto são: • Quantum esgotou • Uma thread de maior prioridade está pronta para executar • Uma thread em execução entra em espera
  36. 36. Cenários de escalonamento • Troca voluntaria • Preempção • Fim do quantum • Fim da thread
  37. 37. Troca Voluntária • Uma thread pode renunciar voluntariamente o uso do processador dando a chance da próxima executar, inserindo um estado de espera em um objeto (o Windows implementa um modelo de objeto para fornecer acesso consistente e seguro para os vários serviços internos implantados) • Objetos podem ser : • Mutex • Processor • Threads • Semáfaros, entre outros. • Os mesmos chamam uma das funções de espera do Windows: WaitForSingleObject ou WaitForMultipleObjects (Pode receber mais de um objeto por parâmetro). Os parâmetros dessas funções é um ou mais objetos e um time-out interval. Os retornos possíveis são: • WAIT_ABANDONED : Ocorre quando um processo tenta tomar posse de um mutex que ainda não foi liberado pelo processo que é seu atual dono, pois o processo que o possui terminou de fazer a execução e esqueceu de liberar o mutex. Então o sistema, em nome do processo dono, libera o mutex para o processo que pediu a posse e o estado do mesmo é setado para não sinalizado. • WAIT_OBJECT_0 : Quando o estado do objeto é setado para sinalizado. • WAIT_TIMEOUT : Quando o time-out interval é esgotado o estado do objeto é setado para não sinalizado. • WAIT_FAILED : A função falhou, para descobrir o erro existe a função getLastError.
  38. 38. Preempção • Nesse cenário de escalonamento, uma thread com prioridade menor é interrompida quando uma thread com prioridade maior fica pronta para executar. Essa situação pode ocorrer pelas seguintes razões: • Uma thread de prioridade alta completa o estado de espera; • A prioridade de uma thread é aumentada ou diminuída. • Em ambos os casos o Windows deve determinar se a thread atual continua executando ou se deve ser interrompida para permitir a execução da thread de maior prioridade. • Threads executando no modo usuário podem interromper as threads de modo kernel, o modo em que a thread executa não importa. • Apenas a Prioridade é o fator que determina. • Quando uma thread é interrompida, ela é posta no começo da fila de threads prontas para a prioridade que estava executando.
  39. 39. Preempção Na figura, a thread com prioridade 18 sai do estado de espera e recupera a CPU, fazendo com que a thread que estava executando (com prioridade 16) seja interrompida. A thread interrompida não vai para o final da fila e sim para o inicio, para que quando a thread em execução termine de executar a mesma possa completar seu quantum.
  40. 40. Fim do quantum • Quando o quantum de uma thread em execução acaba o escalonador deve determinar duas coisas: • Se diminuirá o nível de prioridade da thread que estava em execução • Se irá escalar outra thread para a execução.
  41. 41. Fim do quantum - Reduzindo prioridade • Se a prioridade for diminuída o escalonador irá procurar uma thread mais apropriada para executar. • Por exemplo, uma thread, na fila de prontos, com prioridade mais alta que a nova prioridade da thread que estava em execução
  42. 42. Fim do quantum - Sem reduzir prioridade • Se a prioridade não for reduzida e existirem outras threads com a mesma prioridade na fila de prontos • A thread que estava em execução é colocada no final da fila e o escalonador seleciona a thread que será executada.
  43. 43. Gerenciamento do quantum • O escalonador do Windows usa um contador de ciclos de clock da CPU para manter os tamanhos dos quantums. • Ele também utiliza esse contador para determinar se a thread deverá receber mais um quantum.
  44. 44. Imaginando a seguinte situação • Existem duas threads, 'A' e 'B', com mesmo nível de prioridade. • Estas threads entram no estado de pronto no meio de um intervalo de clock. • A thread 'A' ganha o CPU. • Durante a execução da thread ocorre uma interrupção de sistema. • O que irá acontecer ao final do intervalo de clock.
  45. 45. Escalonador baseado somente no intervalo de clock
  46. 46. Problemas • Neste cenário a thread 'A' foi penalizada de forma injusta de duas maneiras diferentes. • O tempo gasto no tratamento de interrupção é retirado do tempo de execução da thread. • O tempo, dentro do intervalo de clock, em que o sistema estava inativo, é retirado do tempo de execução da thread. • No final do intervalo de clock o escalonador coloca a thread 'B' para executar.
  47. 47. Escalonador baseado em ciclos de clock da CPU
  48. 48. Resultado • Ao final do intervalo de clock o sistema percebe que o número do ciclos de clock de CPU gasto executando a thread foi muito menor que o esperado. • Desta forma ele imagina que a thread começo a executar no meio de um intervalo de clock. • Por isso a thread recebe um acréscimo no quantum igual ao tamanho de um intervalo de clock. Tendo assim a chance de ser executada por um intervalo de clock completo. • No final deste intervalo o escalonador coloca a thread 'B' para executar.
  49. 49. Sistemas MultiProcessador • Em um sistema com um único processador, o escalonamento é relativamente simples: a thread de maior prioridade no estado pronto, será executada. • Em sistemas com múltiplos processadores, o escalonamento é mais complexo, pois o Windows tenta escolher o processador ideal para escalonar a thread, levando em conta os processadores que ela havia ocupado previamente, para aproveitamento de dados da execução anterior que podem se encontrar na cache, bem como a configuração do sistema multiprocessador. • O Windows tenta escalonar as threads do estado pronto de maior prioridade em todas as CPU’s disponíveis, porém garante apenas que, uma das threads de maior prioridade será executada em algum lugar. • Windows mantém a trajetória da thread e o estado do processador em sistemas com múltiplos processadores. • Suporta três diferentes tipos de sistemas com múltiplos processadores (SMT, multicore, e NUMA).
  50. 50. Sistemas SMT e multicore • O Windows usa cinco campos na estrutura de dados KPRCB (Kernel Processor Control Block) para determinar corretamente as decisões de escalonamento quando se trata de topologias de processadores lógicos. • CoresPerPhysicalProcessor • Determina se o processador lógico é parte de um pacote multicore. • Calculado através da CPUID retornado pelo processador, arredondado para potencia de 2. • LogicalProcessorsPerCore • Determina se o processador lógico é parte de um conjunto de SMT. • Processadores Intel com HyperThreading ativado. • Calculado através da CPUID arredondado. • PackageProcessorSet • Preenchido por cada PRCB (Processor Control Block). • Mascara de afinidade que descreve que os processadores lógicos dentro deste grupo pertencem ao mesmo processador físico. • Pacotes são limitados a um grupo. • CoreProcessorSet • Conecta outros processadores lógicos ao mesmo núcleo. • Também chamado de Conjunto de SMT. • GroupSetMember • Define qual máscara de bits, dentro do grupo atual do processador, identifica o processador lógico. • Exemplo: Processador Lógico 3 -> GroupSetMember de 8 (2^3).
  51. 51. Sistemas NUMA • NonUniform Memory Access • Processadores são agrupados em unidades menores chamadas de nós. • Cada nó possui seus próprios processadores e memória. • Os nós são ligados a um grande sistema através de um barramento de interligação de cache-coerente. • São chamados assim pois cada nó tem a sua própria memória local de alta velocidade. • Qualquer processador em qualquer nó pode acessar toda a memória disponível. • A memória local do nó é muito mais rápida para acesso. • O kernel mantém informações sobre cada nó em uma estrutura de dados chamada Knode. • KeNodeBlock é uma variável do kernel que representa uma matriz de ponteiros, para cada estrutura Knode.
  52. 52. Afinidade • Cada thread tem um mascara de afinidade que especifica os processadores nos quais a thread pode ser executada. • A mascara de afinidade da thread é herdada da mascara de afinidade do processo. • Por padrão, todos os processos (e portanto todas as threads) começam com uma máscara de afinidade que é igual ao conjunto de todos os processadores ativos do seu grupo de processador atribuído.
  53. 53. Afinidade • No entanto, para otimizar o desempenho, os aplicativos podem optar por alterar a mascara de afinidade de uma thread. Isto pode ser feito em vários níveis: • SetThreadAffinityMask • Para definir a afinidade de uma thread especifica. • SetProcessAffinityMask • Para definir a afinidade para as threads de um processo especifico. • Gerenciador de tarefas. • No cabeçalho da imagem ao compilar o aplicativo
  54. 54. Afinidade • Cada thread tem três números de CPU armazenadas no bloco de controle da thread no kernel: • Processador ideal • Processador preferido para a execução da thread. • Último processador • Processador na qual a thread foi executada pela ultima vez. • Próximo processador • Processador na qual a thread vai ser executada.
  55. 55. Referências http://technet.microsoft.com/en-us/sysinternals/bb963901.aspx http://www.msuiche.net/2009/01/12/kprcb-structure-modified-in-win7-another-thing-to-fix-into-win32dd/ http://msdn.microsoft.com/en-us/library/windows/desktop/ms687032%28v=vs.85%29.aspx http://www.ehow.com.br/diferenca-entre-processamento-real-processamento-batch-info_48364/ http://msdn.microsoft.com/pt-br/library/windows/desktop/ms686247%28v=vs.85%29.aspx http://msdn.microsoft.com/en-us/library/windows/desktop/ms686223%28v=vs.85%29.aspx http://msdn.microsoft.com/en-us/library/windows/desktop/ms686219(v=vs.85).aspx http://msdn.microsoft.com/en-us/library/windows/desktop/ms686277%28v=vs.85%29.aspx http://ctd.ifsp.edu.br/~marcio.andrey/images/Escalonamento-Processos-IFSP.pdf

×