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

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