Capítulo 5
Transcrição
Capítulo 5
Universidade Federal do Rio de Janeiro Núcleo de Computação Eletrônica Divisão de Assistência ao Usuário Capítulo 5 WIN 32 O objetivo deste capítulo é apresentar os principais elementos, operações e características da WIN32 e suas APIs. Neste capítulo encontram-se uma descrição sucinta dos principais objetos, processos, threads e descrição a arquitetura do Windows NT. OBJETOS O termo Objeto possui diversas conotações, quando se fala a arquitetura da Win32, o termo tem um significado totalmente diferente do significado de Objetos na POO ou COM. Para tornar as coisas um pouco mais complicadas, o termo Objeto s na Win16 é diferente na Win32. Basicamente existem dois tipos de Objetos na Win32: Objetos Kernel e Objetos Gdi/User. OBJETOS KERNEL Os Objetos Kernel são nativos da Win32 e incluem eventos, mapemento de arquivos, 1 2 mailslots , pipes , mutexes, processos, semáforos e threads. A API da Win32 possui várias funções específicas para cada um dos objetos Kernel. 1 Mailslots são repositórios de mensagens, usado para comunicação entre processos. Delphi Pag. 94 Universidade Federal do Rio de Janeiro Núcleo de Computação Eletrônica Divisão de Assistência ao Usuário Antes de estudarmos os objetos Kernel, vamos tecer uma discussão acerdo dos processos na Win32. PROCESSO Pode se entendido como uma instância de um aplicação, podem existir diversos processos ativos na Win32 simultaneamente. Cada processo possui um espaço de endereçamento de até 4GB onde podem ser armazenados dados, cógido, threads, mapeamento de arquivos, DLLs, etc. A princípio, processos são entes inertes que nada executam, cada processo tem acesso a 2GB, o espaço restante é gerenciado pelo sistema operacional. Cada processo possui uma e somente uma Primary Thread (thread primária) que efetua todo o processamento. Quando um processo é criado, o sistema cria a thread primária que por sua vez pode criar outras threads. Para cada thread processada, a Win32 aloca CPU através de Time Slices. Cada time slice recebe o nome de quantum. Na Win32, todo processo possui um manipulador de instância, no Delphi, este manipulador é uma variável global chamada HInstace declarada automaticamente no interior dos programas Delphi. O Hinstace de uma aplicação é seu endereço base, isto é, a posição de memória onde está carregada. No Windows 95/98, o valor de HInstace é normalmente 10x00400000, isto é, o programa geralmente carregado na marca de 4MB. A tabela abaixo apresenta funções que manipulam processos na Win32. Função CreateProcess( ) ExitProcess( ) DuplicateHandle( ) GetCurrentProcessID( ) GetExitCodeProcess( ) GetPriorityClass( ) OpenProcess( ) SetPriorityClass( ) TerminatedProcess( ) Propósito Cria um novo processo e a thread primária. Finaliza o processo corrente e todas as threads. Duplica o handle de um objeto Kernel. Retorna o ID do processo corrente, todo processo possui um único ID, que é mantido pelo sistema até o término do processo. Retorna o status de saída de um processo. Retorna a prioridade de um processo Retorna o handle de um processo especificado pelo ID. Define a prioridade de um processo. Finaliza um processo e elimina todas as threads associadas a ele. MULTITASKING e MULTITHREADING O termo Multitasking(Multitarefa), é usado para descrever a capacidade de um sistema operacional executar várias aplicações concorrentemente. Isso só é possív el pois cada aplicação recebe um pequeno Time Slice, dando a impressão que vária aplicações estão rodando simultaneamente. O conceito de multitarefa não é uma novidade apresentada pelo Windows. A principal diferença da implementação da multitarefa na Win32 para 2 Pipe é um ‘conduíte lógico’ que permite a comunicação entre processos. Delphi Pag. 95 Universidade Federal do Rio de Janeiro Núcleo de Computação Eletrônica Divisão de Assistência ao Usuário as versões anteriores é que a Win32 usa Multitarefa Preemptiva , enquanto que as versões anteriores apresentavam Multitarefa Cooperativa. O termo Multithreading(Multithread ), é usado quando uma aplicação pode criar outras threads. Isso significa que a aplicação pode efetuar diferentes tipos de processamento simultaneamente. Um processo pode ter diversas threads, e cada thread possui um código distinto. Threads podem ter dependências entre si, podem ser sincronizadas. entre si. Ao criar objetos do tipo Kernel, ele passa a existir no espaço de endereçamento e o processo criador, passa a manipular este objeto através de um Handle. Este Handle não pode ser passado para outro processo ou mesmo reutilizado por outro processo que use o mesmo objeto Kernel. Entretanto, um segundo processo poderá obter seu próprio handle a partir de um objeto Kernel existente, usando as APIs apropriadas, como por exemplo, CreateMutex( ) que cria um Mutex nomeado ou não e que retorna seu handle. A API OpenMutex( ) somente retorna o handle de um mutex nomeado, pois esta API passa como parâmetro o nome do Mutex cujo handle está sendo solicitado. Seções Críticas e Mutexes fornecem mecanismos de sincronização entre thrads muito semelhante, exceto pelo fato de que as seções críticas são usadas somente para threads de um único processo. Existe dois pontos a ser considerados quando se escolhe o método de sincronização. Velocidade Seções Críticas são um pouco mais eficientes que mutexes, pois usam o mecanismo de Test/Set para determinar a Exclusão Mútua. Deadloack Se uma thread terminar e não liberar seus recursos, o mutex é considereado abandonado.A thread em estado de espera piode alocar um mutex abandonado, porém, a função WaitForSingleObject( ) retorna o valor WAIT_ABANDONED para o mutex. MULTITAREFA PREEMPTIVA Cada processo pode ter uma ou mais threads. O Windows 95/98 e Windows NT são sistemas operacionais multitarefa, a cada momento existem n threads executando, porém apenas uma está ativa a cada momento e cada thread possui um contexto. O Object Pascal possui uma estrutura chamada TContext que armazena todas as informações sobre o contexto de uma thread, isto é, o estado dos registradores da CPU quando a thread está em execução. Logo, a cada Time Slice o Windows recupera o contexto da thread e continua sua execução até o final do ciclo. Armazenando novamente um TContext. Aplicativos multithreading são aqueles capazes de utilizar as características de multitarefa dos sistema, isto é, cada aplicativo pode executar diferentes tipos de processamento “simultaneamente”. Delphi Pag. 96 Universidade Federal do Rio de Janeiro Núcleo de Computação Eletrônica Divisão de Assistência ao Usuário THREADS E SEUS USOS O uso de threads representa uma grande vantagem para o programador Windows. É possível criar threads secundárias em um aplicação quando for necessário para executar um processamento em background. Podemos citar como exemplos, cálculos em uma planilha ou o processamento de um texto durante o processo de impressão. O principal objetivo do uso de threads é executar algum processamento em background e oferecer a melhor resposta possível para o processamento da interface com o usuário. OBJETO TTHREAD O Delphi encapsula a Thread API que manipulam threads em um objeto chamado TThread. A descrição do objeto TThread está na unit Classes : Type TThread = class private FHandle: THandle; FThreadID: THandle; FTerminated: Boolean; FSuspended: Boolean; FFreeOnTerminate: Boolean; FFinished: Boolean; FReturnValue: Integer; FOnTerminate: TNotifyEvent; FMethod: TThreadMethod; FSynchronizeException: TObject; procedure CallOnTerminate; function GetPriority: TThreadPriority; procedure SetPriority(Value: TThreadPriority); procedure SetSuspended(Value: Boolean); protected procedure DoTerminate; virtual; procedure Execute; virtual; abstract; procedure Synchronize(Method: TThreadMethod); property ReturnValue: Integer read FReturnValue write FReturnValue; property Terminated: Boolean read FTerminated; public constructor Create(CreateSuspended: Boolean); destructor Destroy; override; procedure Resume; procedure Suspend; procedure Terminate; function WaitFor: LongWord; property FreeOnTerminate: Boolean read FFreeOnTerminate write FFreeOnTerminate; property Handle: THandle read FHandle; property Priority: TThreadPriority read GetPriority Delphi Pag. 97 Universidade Federal do Rio de Janeiro Núcleo de Computação Eletrônica Divisão de Assistência ao Usuário write SetPriority; property Suspended: Boolean read FSuspended write SetSuspended; property ThreadID: THandle read FThreadID; property OnTerminate: TNotifyEvent read FonTerminate write FOnTerminate; end; O objeto TThread é descendente direto de TObject e não é um componente. Observe que o método TThread.Execute( ) é um método abstrato, isto significa que toda a classe TThread é abstrata, isso significa que não é possível criar uma instância de TThread, só é possível criar instâncias dos descendentes de TThread. A maneira mais simples de criar um descendente de TThread, é selecionar o objeto Thread na janela New Itens, que pode ser selecionada através do comando File/New . Ao selecionar o objeto Thread, uma janela solicitará o nome do novo objeto, então, o Delphi cria uma nova unit que contém o objeto recém definido. Veja o exemplo abaixo: type MinhaThread = class(TThread) private { Private declarations } protected procedure Execute; override; end; Observe que o método Execute é declarado como Override. Deve ser criado um descendente deste método. Suponha que o método Execute, efetuará um cálculo como o código abaixo: Delphi Pag. 98 Universidade Federal do Rio de Janeiro Núcleo de Computação Eletrônica Divisão de Assistência ao Usuário Procedure TminhaThread.Execute; Var I : Integer; Begin For I := 1 to 20000 do Inc(Answer,Round(Abs(Sin(Sqrt,I))))); End; Para executar esta thread, basta chamar o constructor Create( ), veja o exemplo: Procedure TForm1.Button1Click (Sender: TObject); Var NovaThread : TMinhaThread; Begin NovaThread := TMinhaThread.Create(False); End; Para executar a aplicação basta ativar o botão, observe que o Form pode ser movido ou movimentado enquanto o cálculo e feito em background. INSTÂNCIAS DE THREADS O método Execute( ) dos objetos TThread formar um stack individual para cada thread em execução, logo, não se corre o risco de sobrescrita de variáveis nem precedência entre threads. FINALIZAÇÃO DE THREADS Uma thread é considerada finalizada quando o método Execute( ) termina sua execução. GERÊNCIA DE MEMÓRIA NA WIN32 Delphi Pag. 99 Universidade Federal do Rio de Janeiro Núcleo de Computação Eletrônica Divisão de Assistência ao Usuário O Win32 possui um modelo de memória plana, isto é, NÃO existe a limitação dos fatídicos 64KB para estruturas de dados. Um processo pode endereçar até 4GB. Na Win32 existem mais endereços de memória que memória física propriamente dita, ou seja. A Win32 usa o esquema de Endereços Virtuais. MODELO DE MEMÓRIA PLANA. O ”mundo” 16 bits usa o modelo de memória segmentada, onde os endereços são representados pelo par Segmento:Offset. Onde Segmento refere-se ao endereço base, e offset o número de bytes de deslocamento a partir deste endereço. O problema deste modelo é a falta de clareza e o, limite de 64KB para estruturas de dados. Sob o modelo de memória plana, esta limitações não existem, cada processo possui um espaço de endereçamento de até 4GB e cada endereço representa um porção de memória. COMO FUNCIONA O GERÊNCIA DE MEMÓRIA NA WIN32? Através do uso da memória virtual, cada processo aloca 4GB de endereços virtuais. Os 2GB da porção mais alta, pertence ao Windows. A porção mais baixa é o local onde a aplicação reside e onde se aloca memória. Uma das grandes vantagens deste modelo é que uma thread NÃO pode acessar memória associada a outro processo. É importante ressaltar que um processo não usa os 4Gb de memória virtual, porém pode acessar qualquer um dos endereços associados a ele. A quantidade de memória disponível para um processo depende basicamente de : • Quantidade de memória RAM; • Tamanho do arquivo de paginação (Swap File) MEMÓRIA VIRTUAL A Win32 possui uma série de funções de baixo nível que permitem manipular a memória virtual de um processo. A memória na Win32 existe sob um dos três estados: Free Memória disponível para ser reservada ou comitada Reserved Faixa de endereços alocadas para uso posterior. Os endereços reservados são protegidos de alocação por outros processos. Esta memória não pode ser acessada fisicamente por um processo pois ela ainda não está associada a memória física. Commited Memória alocada e associada a memória física. A memória comitada pode ser acessada por um processo. A figura abaixo ilustra um esquema (simplificado) do conceito de memória virtual. As principais funções da Win32 para memória virtual são: Função VirtualAlloc( ) Delphi Propósito Reserva/Comita páginas de memória no espaço de endereçamento Pag. 100 Universidade Federal do Rio de Janeiro Núcleo de Computação Eletrônica Divisão de Assistência ao Usuário VirtualFree( ) VirtualLock( ) VirtualUnlock( ) VirtualQuery( ) VirtualProtect( ) virtual de um processo. Libera/”Descomita” páginas de memória no espaço de endereçamento virtual de um processo. Bloqueia uma região do espaço de endereçamento de um processo, evita que ocorra swap para o page file. Evita que ocorram page faults nos próximos acessos a essa região Libera uma região de memória permitindo o swap. Retorna a faixa de endereçamento virtual de um processo. Troca a proteção de acesso de uma região de páginas comitadas. HEAPS Heaps são blocos contíguos de memória, onde blocos menores podem ser alocados. Heaps gerenciam eficientemente a alocação e manipulação de memória dinâmica. Existem diversas funções na Win32 que manipulam a Heap, consulte a tabela abaixo: Função HeapCreate( ) HeapAlloc( ) HeapReAlloc( ) HeapFree( ) HeapDestroy( ) Propósito Reserva um bloco contíguo de memória na espaço de endereçamento virtual. Aloca fisicamente memória para a porção inicial deste bloco. Aloca um bloco de memória da Heap. Realoca um bloco de memória na Heap, permite redimensionar ou alterar as propriedades da Heap. Libera um bloco de memória alocado na Heap Destroy a Heap. NOTA: Existem inúmeras diferenças de implementação entre a Win32 do Windows 98 e do Windows NT, esta diferenças gera lmente estão associadas a segurança e velocidade de acesso. MANIPULAÇÃO DE ERROS NA WIN32 A maioria da funções da Win32 retornam valores booleanos que indicam se a função foi executada com sucesso ou não. Caso a função não obtenha sucesso ela retorna False. Para obter o valor do código de erro de uma thread, usa -se a função GetLastError( ) da Win32,. Este código erro é mantido por cada thread, logo a função GetLastError( ) deve ser no contexto da thread que apresentou o erro. O exemplo abaixo ilustra o u sa da função: If Not CreateProcess(CommandLine,nil,nil,nil,False, NORMAL_PRIORITY_CLASS, nil,nil, StartupInfo, ProcessInfo) Then Raise Exception.Create('Erro na criação do processo :'+ InToStr(GetLastError)); Delphi Pag. 101 Universidade Federal do Rio de Janeiro Núcleo de Computação Eletrônica Divisão de Assistência ao Usuário O código acima tenta criar um processo através de uma null-terminated string(CommandLine), caso falhe, uma exception é gerada e esta gera o código de erro retornado por GetLastError( ). Delphi Pag. 102
Documentos relacionados
Slides Grupo 3 - Blog UNIFIMES
No Windows quase todas as bibliotecas são DLLs, desde a biblioteca de sistema ntdll.dll que é carregado em todo processo, até as bibliotecas de altos níveis de funções comuns que se destinam a pe...
Leia mais