Você está na página 1de 40

Instituto Superior de Engenharia de Lisboa

Departamento de Engenharia Electrnica e das Comunicaes


SECO DE ENGENHARIA DE SISTEMAS

Modelo Computacional do Windows NT


(1 verso)

Nuno Oliveira Lus Assuno Lus Osrio Porfrio Filipe

SES/DEEC/ISEL, Maio de 1997

Modelo Computacional do Windows NT

ndice

1. WIN32, WIN32S, WINDOWS 95 E WINDOWS NT........................................................4 1.1 WIN32S .............................................................................................................................4 1.2 WINDOWS NT ....................................................................................................................4 1.2.1 Arquitectura do sistema Windows NT........................................................................4 1.3 WINDOWS 95 .....................................................................................................................5 2. PROCESSOS.........................................................................................................................6 2.1 MODELO DE OBJECTOS NO WINDOWS NT..........................................................................6 2.2 FUNO CREATEPROCESS .................................................................................................9 2.3 FUNO EXITPROCESS ....................................................................................................14 2.4 FUNO GETEXITCODEPROCESS.....................................................................................14 3. THREADS ...........................................................................................................................15 3.1 ESTADOS DE EXECUO DOS THREADS ............................................................................16 3.1.1 Prioridades ..............................................................................................................16 3.2 CRIAO DE THREADS UTILIZANDO A WIN 32 API ..........................................................17 3.2.1 Funo CreateThread..............................................................................................17 3.2.2 Funo ExitThread ..................................................................................................17 3.3 PROBLEMAS EXISTENTES COM A BIBLIOTECAS DO C/C++................................................17 3.3.1 Funo _beginthreadex ...........................................................................................18 3.3.2 Macro/funo BEGINTHREADEX..........................................................................18 3.3.3 Funo _endthreadex...............................................................................................19 3.3.4 Funes _beginthread e _endthread........................................................................20 3.4 FUNO GETEXITCODETHREAD .....................................................................................20 3.5 FUNO SUSPENDTHREAD ..............................................................................................20 3.6 FUNO RESUMETHREAD................................................................................................20 4. MECANISMOS DE SINCRONIZAO.........................................................................21 4.1 REGIES CRITICAS (CRITICAL SECTION)...........................................................................21 4.1.1 Funo InitializeCriticalSection..............................................................................21 4.1.2 Funo DeleteCriticalSection..................................................................................21 4.1.3 Funo EnterCriticalSection ...................................................................................21 4.1.4 Funo LeaveCriticalSection...................................................................................21 4.1.5 Exemplo....................................................................................................................21
DEEC - Seco de Engenharia de Sistemas Maio, 1997 2

Modelo Computacional do Windows NT 4.2 SINCRONIZAO DE THREADS UTILIZANDO OBJECTOS DO NCLEO ...................................23 4.2.1 Funo WaitForSingleObjects.................................................................................23 4.2.2 Funo WaitForMultipleObjects .............................................................................24 4.3 EXCLUSO MTUA (MUTEX) ...........................................................................................25 4.3.1 Funo CreateMutex ...............................................................................................25 4.3.2 Funo OpenMutex..................................................................................................26 4.3.3 Funo ReleaseMutex..............................................................................................26 4.3.4 Exemplo....................................................................................................................27 4.4 SEMFOROS (SEMAPHORES) ............................................................................................28 4.4.1 Funo CreateSemaphore .......................................................................................28 4.4.2 Funo OpenSemaphore..........................................................................................29 4.4.3 Funo ReleaseSemaphore......................................................................................29 4.4.4 Exemplo....................................................................................................................30 4.5 EVENTOS (EVENTS)..........................................................................................................32 4.5.1 Funo CreateEvent ................................................................................................33 4.5.2 Funo OpenEvent...................................................................................................33 4.5.3 Funo SetEvent ......................................................................................................33 4.5.4 Funo ResetEvent...................................................................................................33 4.5.5 Funo PulseEvent ..................................................................................................33 4.6 FAMLIA DE FUNES INTERLOCKED ................................................................................34 5. COMUNICAO ENTRE PROCESSOS .......................................................................34 6. BIBLIOGRAFIA.................................................................................................................35 7. ANEXO A - GUIA DE UTILIZAO BSICA DO AMBIENTE VISUAL C++.......36 7.1 INICIAR UM NOVO PROJECTO ............................................................................................37

DEEC - Seco de Engenharia de Sistemas

Maio, 1997

Modelo Computacional do Windows NT

1. WIN32, WIN32s, Windows 95 e Windows NT


Apesar de o sistema operativo Windows NT ter nascido no final da dcada de 80, s nos ltimos anos que a sua importncia tem vindo a ser cada vez maior. A verso 3.51, mais tarde consolidada e estabilizada na verso 4.0, hoje um sistema operativo j usado em grande escala, correndo em mquinas com as mais variadas arquitecturas, incluindo arquitecturas multi-processador. Neste texto feita uma primeira abordagem ao modelo computacional do sistema operativo Windows NT, com nfase para os servios disponveis na interface WIN32 API, que permitem manipular os objectos principais, Processos, Threads e alguns mecanismos de sincronizao entre Processos e/ou Threads. Atendendo que o Sistema Windows 95 tem uma quase compatibilidade com o sistema Windows NT, tendo disponvel um subconjunto dos servios existentes no sistema Windows NT, os exemplos aqui apresentados podem ser experimentados no ambiente Windows 95. 1.1 WIN32s O WIN32s foi a primeira plataforma a permitir a execuo de aplicaes 32 bits utilizando a interface WIN32. Esta plataforma formada por um conjunto de bibliotecas dinmicas (DLL) que permite adicionar a interface WIN32 ao sistema de 16 bits Windows 3.x tornando, assim possvel, a execuo de aplicaes de 32 bits. O WIN32s, no adiciona caractersticas relevantes ao sistema operativo, devido s limitaes do sistema Windows 3.x. Vrias funes da interface WIN32 no esto implementadas no WIN32s, pelo que devolvem sempre NULL. A plataforma WIN32s , neste momento, considerada obsoleta. 1.2 Windows NT 1.2.1 Arquitectura do sistema Windows NT O Windows NT tem uma arquitectura flexvel onde esto reflectidos os grandes desenvolvimentos tecnolgicos e de engenharia de software dos ltimos anos. O modelo Cliente/Servidor e o conceito de objectos esto presentes em quase toda a sua estrutura. Do ponto de vista de interface um sistema totalmente adequado a ambientes de software Cliente Servidor, onde o subsistema WIN32 API desempenha um papel primordial. um sistema construdo usando parcialmente o conceito de microkernels, isto , onde a componente kernel mnima criando uma virtualizao da componente hardware e a responsabilidade de gerir o(s) processadore(s). As restantes componentes do sistema so mdulos com funcionalidades bem definidas e que interactuam entre si usando o modelo Cliente/Servidor. Na figura seguinte apresentada a arquitectura do sistema.

DEEC - Seco de Engenharia de Sistemas

Maio, 1997

Modelo Computacional do Windows NT


Logon Process DOS/Win16 Subsystem Security System OS/2 Subsystem POSIX Subsystem

POSIX application

Message Passing

Win32 Subsystem User mode Kernel mode Executive Services I/O Manager
Object Manager Security Reference Monitor Process Manager Virtual Memory Manager Local Procedure Call File Systems Cache Manager Device Drivers Network drivers

Kernel
Hardware Abstration Layer (HAL)

Hardware

Figura 1 - Arquitectura do sistema Windows NT

O Windows NT, um sistema operativo integralmente concebido pela Microsoft sem qualquer herana do MSDOS, foi a segundo plataforma a suportar a interface WIN32. No entanto, este novo sistema operativo requer especificaes hardware relativamente altas podendo este factor representar um obstculo adopo deste novo sistema por parte da grande maioria dos utilizadores. 1.3 Windows 95 O Windows 95 aparece como o sucessor do Windows 3.x, suportando desde logo a interface WIN32. Apesar da melhor implementao da interface WIN32 em relao ao WIN32s, o Windows 95 no suporta na globalidade, a implementao do WIN32 API. A razo reside no facto deste sistema operativo, ao contrrio do Windows NT, ser dirigido ao grande mercado de utilizadores possuindo mquinas de baixas especificaes (mnimo CPU 386 e 4Mb RAM). Em suma, para que o Windows 95 se possa executar numa mquina com 4Mb, obrigou a Microsoft a no implementar, na totalidade, algumas das funes da interface WIN32.

DEEC - Seco de Engenharia de Sistemas

Maio, 1997

Modelo Computacional do Windows NT

2. Processos
Um processo em Windows 95-NT apresenta-se como entidade de encapsulamento de um ou mais fios de execuo (threads), um espao de endereamento de 4Gb e informao sobre outros recursos.
Processo B

Processo B CreateProcess(, xpto.exe,) Primary thread Thread 1

Thread 2

CreateThread()

Thread 3

xpto.exe

Um processo criado pelo servio CreateProcess() do WIN32 , a partir de um ficheiro executvel (ficheiro executvel - EXE Microsoft). Todos os fios de execuo (thread) de um processo partilham todos os recursos acessveis pelo processo. Como exemplos de recursos partilhados temos os ficheiros, mecanismos de comunicao e sincronizao, memria, etc. Quando um processo WIN32 criado o sistema cria automaticamente um thread, primary thread, podendo este criar outros threads que se executaro em concorrncia. Quando todos os threads de um processo terminarem este automaticamente eliminado pelo sistema. 2.1 Modelo de Objectos no Windows NT Como em todos os sistemas operativos o Windows NT usa processos como entidades que realizam tarefas. Cada processo tem atribudo um conjunto de recursos que lhe permitam realizar uma tarefa em particular, nomeadamente um thread que executa as aces do programa e um espao de endereamento com o cdigo e os dados do programa. Durante a execuo do thread, este pode adquirir recursos adicionais para o processo atravs da criao de objectos ou a abertura de descritores (HANDLES) de objectos j existentes. Os descritores de objectos so nicos no processo e representam o mecanismo de acesso aos recursos do sistema, isto , podem ser usados para chamar os servios nativos de manipulao desses recursos.

DEEC - Seco de Engenharia de Sistemas

Maio, 1997

Modelo Computacional do Windows NT O sub-sistema Win32 um processo em Windows NT que actua como um servidor para as aplicaes que se executem no sistema. Quando uma aplicao chama uma rotina do WIN32 API, que directa ou indirectamente cria um objecto, o sub-sistema WIN32 chama o servio de um objecto nativo do NT.
Aplicao

Win32 Subsystem

Create Process

Create File

User mode Kernel mode

Executive Services I/O Manager


Object Manager Security Process Reference Manager Monitor Virtual Memory Manager Local Procedure Call File Systems Cache Manager Device Drivers Network drivers

Kernel
Hardware Abstration Layer (HAL)

Hardware

Durante a execuo do servio, o gestor de objectos do Windows NT realiza as seguintes funes: Atribuio de memria a um objecto; Associar um descritor de segurana ao objecto que especifica quem pode us-lo e que operaes so permitidas; Criao e manuteno de uma directoria de objectos, onde so guardados os seus nomes; Criao de um descritor (HANDLE) do objecto que devolvido aplicao; Assim, as aplicaes que acedem ao WIN32 API usam descritores (HANDLES) como indireces para os recursos do sistema, por exemplo, janelas, cursor do rato, cones, processos, threads, semforos, mutex, eventos, etc. Desta forma todas as aces realizadas por uma aplicao que afecta um objecto podem ser controladas pelo gestor de objectos que: Protege o objecto, isto , cada vez que um thread usa um handle, o gestor de objectos valida os direitos que a thread tem sobre o objecto. Monitoriza quem est a utilizar os objectos apagando-os quando eles j no so mais necessrios (o gestor de objectos no apaga um objecto, enquanto existir um processo com handle vlido para ele). Monitoriza a utilizao dos recursos. Cada vez que um thread obtm (open) um handle para um objecto, a memria necessria para a sua utilizao atribuda ao processo a que pertence o thread. Os recursos podem ser limitados atravs de aces de administrao de sistema.

DEEC - Seco de Engenharia de Sistemas

Maio, 1997

Modelo Computacional do Windows NT Em NT, tal como o modelo de acesso a ficheiros em Unix, quando um processo cria um objecto ou abre um handle para um objecto j existente o processo deve especificar os direitos de acesso pretendidos (Read, Write, Execute, Delete, Suspende ou Terminate, etc.). Em NT, cada processo tem uma tabela de objectos, onde em cada entrada existem referncias para os objectos criados ou abertos por esse processo, as permisses de acesso aos objectos e a indicao se os objectos so ou no herdveis para outros processos ou Threads. Um handle um ndice da tabela de objectos como indicado na figura seguinte.
Permisses de Acesso Processo A Herana Thread A Thread B File A

Handle 0 Handle 1 Handle 2

Tabela de Objectos

Na figura seguinte apresentada a situao existente quando dois processos partilham um objecto, neste caso um Mutex. Dois processos partilham um objecto quando ambos abrem handles para o mesmo. Quando um processo cria um objecto decide se o handle do objecto pode ser herdado por outro processo que eventualmente venha a ser criado. Quando um processso termina, o gestor de objectos activa um mtodo que fecha todos os handles existentes na tabela de objectos. Cada vez que que um processo abre um handle para um objecto o gestor de objectos incrementa um contador associado ao objecto. Quando o processo termina e fecha o handle do objecto o gestor de objectos decrementa o contador. Quando o contador atingir zero, o gestor de objectos apaga o objecto, libertando os recursos que o objecto eventualmente detinha.
Processo A Processo B

Handle 0 Handle 1 Handle 2

Thread A Thread B Mutex Referncias =2 Tabela de Objectos do Processo A

Handle 0 Handle 1 Handle 2

Thread B

Tabela de Objectos do Processo B

DEEC - Seco de Engenharia de Sistemas

Maio, 1997

Modelo Computacional do Windows NT 2.2 Funo CreateProcess Quando um thread evoca esta funo, o ncleo cria um objecto processo, objecto este que ser utilizado, pelo ncleo, na gesto do novo processo. O sistema atribui um espao de endereamento virtual de 4Gb e sobre este espao mapeia o cdigo, dados e as bibliotecas dinmicas necessrias ao executvel. De seguida o ncleo cria a primeira thread deste processo. Este thread ser responsvel pela a execuo do cdigo de arranque do C (startup C code) chamando de seguida a funo WinMain ou a funo main, no caso de um aplicao de terminal.
BOOL CreateProcess( LPCTSTR LPTSTR LPSECURITY_ATTRIBUTES LPSECURITY_ATTRIBUTES BOOL DWORD LPVOID LPCTSTR LPSTARTUPINFO LPPROCESS_INFORMATION ); lpApplicationName, lpCommandLine, lpProcessAttributes, lpThreadAttributes, bInheritHandles, dwCreationFlags, lpEnvironment, lpCurrentDirectory lpStartupInfo, lpProcessInformation

No primeiro parmetro lpApplicationName pode ser indicado o nome do ficheiro executvel. Este nome dever obrigatoriamente possuir a extenso EXE. A funo assume que este executvel se encontra na directoria corrente, no o pesquisando em qualquer outra directoria, salvo se o nome for precedido da sua localizao (especificao do pathname completo). Se o executvel for encontrado a funo CreateProcess passa o argumento lpCommandLine como linha de comandos do programa. Note que, no obrigatrio que o segundo argumento possua o nome do executvel como acontece habitualmente.
CreateProcess(xpto.exe, arg1 arg2, );

int main (int argc, char *argv[]); { }

argv[0] = arg1 argv[1] = arg2

DEEC - Seco de Engenharia de Sistemas

Maio, 1997

Modelo Computacional do Windows NT


#include <stdio.h> #include <windows.h> #include <conio.h> void main() { STARTUPINFO si;

// // SECURITY_ATTRIBUTES procA, thA; // // // PROCESS_INFORMATION piA; // //

permite definir atributos da janela do novo processo descritor de segurana e mecanismo de herana para o novo processo e sua thread primria Handles e Identificadores globais do novo processo

// usar a funcao do Win 32 API para fazer fill de memria ZeroMemory(&si, sizeof(si)); // STARTUPINFO por omisso si.cb = sizeof(si); procA.nLength = sizeof(procA); procA.lpSecurityDescriptor = NULL; // permisses por defeito procA.bInheritHandle = TRUE; // Novo processo herdvel pelos // seus filhos thA.nLength=sizeof(thA); thA.lpSecurityDescriptor = NULL; // permisses por defeito thA.bInheritHandle = FALSE; // A thread principal do novo // processo no herdvel pelos // processos filhos do novo processo printf("In world without frontiers who need's gates ?\n"); if (!CreateProcess( "C:\\Program Files\\MS Office\\Office\\Winword\\WINWORD.EXE", NULL,&procA, &thA, FALSE, 0,NULL,NULL, &si, &piA) ) { printf("nao criou\n"); ExitProcess(-1); } printf("Another world, but the same bugs\n"); CloseHandle(piA.hProcess); // fechar o Handle do novo processo CloseHandle(piA.hThread); // fechar o Handle da threa principal _getch(); } Ficheiro 1 - RunWinWord.cpp

Quando o primeiro parmetro tomar o valor NULL, a primeira componente do segundo parmetro define o executvel e as restantes, separadas por espao, os argumentos. Se o nome no possuir qualquer extenso a extenso EXE assumida e o executvel ser pesquisado pela seguinte ordem: 1. Directoria contendo o executvel do processo que evoca a funo CreateProcess. 2. Directoria corrente do processo que evoca a funo. 3. Directoria system do Windows 4. Directoria do Windows 5. Directorias indicadas na varivel de ambiente PATH.

DEEC - Seco de Engenharia de Sistemas

Maio, 1997

10

Modelo Computacional do Windows NT


#include <stdio.h> #include <windows.h> #include <conio.h> void main() { STARTUPINFO si; // atributos da janela do novo processo SECURITY_ATTRIBUTES procA, thA; // descritor de segurana e mecanismo // de herana para o novo processo e sua // thread primria PROCESS_INFORMATION piA; // Handles e Identificadores globais // do novo processo // usar a funcao do Win 32 API para fazer fill de memria ZeroMemory(&si, sizeof(si)); // STARTUPINFO por omisso si.cb = sizeof(si); procA.nLength = sizeof(procA); procA.lpSecurityDescriptor = NULL; // permisses por defeito procA.bInheritHandle = TRUE; // Novo processo herdvel pelos // seus filhos thA.nLength=sizeof(thA); thA.lpSecurityDescriptor = NULL; // permisses por defeito thA.bInheritHandle = FALSE; // A thread principal do novo // processo no herdvel pelos // processos filhos do novo processo if (!CreateProcess(NULL, "C:\\Projects\\EscreveArgs\\Debug\\EecreveArgs.exe A B C", &procA,&thA,FALSE,CREATE_NEW_CONSOLE,NULL,NULL, &si, &piA) ) { printf("nao criou\n"); EndProcess(-1); } CloseHandle(piA.hProcess); // Fechar o Handle do novo processo CloseHandle(piA.hThread); // Fechar o Handle da Thread principal _getch(); } Ficheiro 2 - CreateProcess.cpp

O programa EscreveArgs.exe apresentado em seguida um programa com as convenes normais em C.


#include <stdio.h> #include <conio.h> void main(int argc, char *argv[]) { int i; printf("N de ARGS=%d\n",argc); for (i=0; i< argc;i++) printf("%s\n",argv[i]); _getch(); } Ficheiro 3 - EscreveArgs.cpp

DEEC - Seco de Engenharia de Sistemas

Maio, 1997

11

Modelo Computacional do Windows NT Os parmetros lpProcessAttributes e lpThreadAttributes permitem indicar quais os atributos de segurana a serem associados, respectivamente, ao novo processo e ao primeiro thread desse processo. O parmetro bInheritHandles permite indicar se o novo processo herda todos os descritores (handles) herdveis. O parmetro dwCreationFlags permite o controlo da prioridade e da criao do processo filho. O valor passado neste parmetro pode ser obtido pela composio (operao or) das seguintes flags. CREATE_DEFAULT_ERROR_MODE O novo processo no vai herdar o modo de controlo de erros do processo pai (ver a funo SetErrorMode). O novo processo vai ter uma nova consola em vez de herdar a consola do processo pai. Esta flag no pode ser utilizada com a flag DETACHED_PROCESS. O novo processo a raiz de um novo grupo de processos. O grupo de processos inclui todos os descendentes do novo processo. O identificador do grupo de processos o mesmo do processo raiz. Os grupos de processos so utilizados pela funo GenerateConsoleCtrlEvent para inibir o envio do Ctrl+C e Ctrl+Break a um grupo de processos consola.. Apenas tem significado quando se est a evocar aplicaes a 16 bits. Se especificada o novo processo executa-se numa mquina DOS virtual (VDM - Vitual DOS Machine) privada. Por omisso todas as aplicaes de 16 bits partilham a mesma VDM. Windows NT: Vlida apenas na execuo de aplicaes de 16 bits. Se est indicada a opo DefaultSeparateVDM como verdadeira na seco WIN.INI, esta flag permite alterar este comportamento e executar o novo processo na mquina de DOS virtual partilhada. O thread primrio, do novo processo, criado no estado suspenso e no executado at a funo ResumeThread ser chamada. Se utilizada indica que o bloco de ambiente, referido pelo parmetro lpEnvironment, utiliza caracteres em Unicode. Caso contrrio utilizada a codificao ANSI. Indica que o processo pai vai actuar como um debugger. O sistema notificar, o processo pai,
Maio, 1997 12

CREATE_NEW_CONSOLE

CREATE_NEW_PROCESS_GROUP

CREATE_SEPARATE_WOW_VDM

CREATE_SHARED_WOW_VDM

CREATE_SUSPENDED

CREATE_UNICODE_ENVIRONMENT

DEBUG_PROCESS

DEEC - Seco de Engenharia de Sistemas

Modelo Computacional do Windows NT sobre todos os eventos de depurao. S o thread que criou o processo poder chamara funo WaitForDebugEvent. DEBUG_ONLY_THIS_PROCESS Equivalente anterior, mas s os eventos relacionados com o processo filho sero entregues ao pai. Para processos em modo consola. O processo no tem acesso consola do processo pai. O novo processo pode utilizar a funo AllocConsole para criar uma nova consola. No pode ser utilizada em conjunto com CREATE_NEW_CONSOLE.

DETACHED_PROCESS

Os processos tm por omisso a prioridade NORMAL_PRIORITY_CLASS excepto quando o processo pai possui a prioridade IDLE_PRIORITY_CLASS em que o filho herda esta prioridade. A prioridade pode ser alterada utilizado uma das seguintes flags. IDLE_PRIORITY_CLASS Indica um processo cujos threads se executam s quando o sistema est livre (idle). A classe de prioridades IDLE herdada pelos processos filhos. Processo normal sem necessidades de escalonamento especiais. Indica um processo que desempenha tarefas urgentes que necessitam de correr imediatamente, por exmplo o thread do gestor de tarefas activa-se imediatamente aps o utilizador carregar em Ctrl+ESC. Indica um processo com a mas alta prioridade possvel. Os threads com este nvel de prioridade retiram o processador a todos os threads dos outros processos incluindo os do sistema operativo desempenhando tarefas importantes. Se os threads, com esta prioridade, ocupam o processador durante bastante tempo, podem conduzir a situaes como caches que no foram ainda actualizados em disco e o rato pode no responder.

NORMAL_PRIORITY_CLASS HIGH_PRIORITY_CLASS

REALTIME_PRIORITY_CLASS

O parmetro lpEnvironment refere um bloco de memria contendo as variveis de ambiente na forma <NOME>=<VALOR>. Se for passado o valor NULL o novo processo herda o conjunto de variveis de ambiente do pai. O parmetro lpCurrentDirectory permite ao processo pai especificar qual a directoria de trabalho do processo filho. No caso de ser passado o valor NULL o processo filho herda a directoria de trabalho do pai. O parmetro lpStartupInfo aponta para uma estrutura do tipo STARTUPINFO especificando os atributos da janela principal do novo processo (para descrio mais pormenorizada consultar bibliografia). O ltimo parmetro, lpProcessInformation, referncia uma estrutura do tipo PROCESS_INFORMATION contendo informaes de identificao do novo processo. A estrutura possui os descritores do processo criado (hProcess) e do respectivo thread

DEEC - Seco de Engenharia de Sistemas

Maio, 1997

13

Modelo Computacional do Windows NT principal (hThread) assim como os seus identificadores globais (dwProcessId, dwThreadId). typedef struct _PROCESS_INFORMATION { HANDLE hProcess; HANDLE hThread; DWORD dwProcessId; DWORD dwThreadId; } PROCESS_INFORMATION;

2.3 Funo ExitProcess Um processo termina quando um dos seus threads evoca esta funo. Todos os outros threads so obrigados a terminarem aps a chamada desta funo.
VOID ExitProcess( UINT uExitCode );

O processo termina tendo como valor de sada o valor indicado no argumento. Esta funo automaticamente chamada pelo cdigo de arranque do C quando terminam as funes WinMain ou main, no caso de aplicaes em modo terminal. 2.4 Funo GetExitCodeProcess
BOOL GetExitCodeProcess( HANDLE hProcess, LPDWORD lpExitCode );

Quando um processo deixa de estar em execuo, o processo pai apenas pode determinar o seu estado de terminao atravs da funo GetExitCodeProcess. O primeiro parmetro da funo identifica o processo e o segundo ser preenchido com o valor de terminao da execuo do processo. No caso do processo, identificado por hProcess, ainda no ter terminado devolvido, em lpExitCode, o valor STILL_ACTIVE.

DEEC - Seco de Engenharia de Sistemas

Maio, 1997

14

Modelo Computacional do Windows NT

3. Threads
Os threads (fios de execuo) tambm designados de processos leves corresponde s entidades executivas do ncleo que suporta o WIN32. Todos os programas WIN32 possuem pelo menos um processo leve (thread) em execuo. Cada processo leve pode dar origem a novos threads, podendo permanecer activos durante toda a vida do processo a que pertencem ou podem terminar aps a concluso da sua tarefa. Os threads existem no contexto dos processos e so as entidades eleitas pelo ncleo para atribuio do CPU - escalonamento. Uma das diferenas entre processos e threads reside na partilha/acesso a recursos. O espao de endereamento entre processos disjunto, enquanto que para os threads este comum (partilhado).
No UNIX Processo A
dados

Processo B
dados

Processo C
dados

Pthreads

Ncleo do UNIX

No WIN32 Processo
dados

Todos os fios de execuo (threads partilham o mesmo espao de endereamento

WIN32
Esta partilha restrita aos threads que se encontram no mesmo ambiente de execuo., isto , os threads existem no contexto de um processo. Considerando a terminologia do WIN32, o ambiente de execuo que engloba um ou mais threads recebe a designao de processo.
DEEC - Seco de Engenharia de Sistemas Maio, 1997 15

Modelo Computacional do Windows NT 3.1 Estados de execuo dos Threads Um thread a entidade escalonada para execuo pelo kernel. Na figura seguinte apresentado o ciclo de vida de um thread, indicando os estados e as condies de transio de estado que o mesmo pode ter desde a sua criao at sua terminao.
Cria e inicializa um objecto thread INITIALIZED Reinicializa TERMINATED WAITING Fim de Execuo Sem Recurso Espera por Objecto Recurso Disponvel Coloca na lista Ready READY Objecto Sinalizado Escalonado para execuo

TRANSITION Preempted ou fim de Time Slice Preeempted

RUNNING

Atribuio de processador

STANDBY

INITIALIZED READY STANDBY

Estado do thread aps a sua criao. Fila com os threads que esperam vez para execuo. Quando o Dispatcher procura threads para execuo, procura os que esto neste estado. Prximo Thread seleccionado para execuo num processador. Quando o processador estiver livre feita a comutao de contexto passando o thread ao estado RUNNING. Thread em execuo at o kernel lhe fazer preempted para executar outro thread mais prioritrio, fim de time slice, terminao do thread ou o thread se suspender voluntariamente. Thread que espera voluntariamente um objecto para se sincronizar ou que foi preempted por fim de time slice. Thread que est pronto a executar-se, mas os recursos, por exemplo memria, que necessita no esto disponveis. Fim de execuo. Aps a terminao o objecto thread pode ou no ser apagado, conforme haja ou no referncias para o mesmo. Se o objecto ainda no foi apagado pode voltar a ser iniciado.

RUNNING

WAITING TRANSITION TERMINATED

3.1.1 Prioridades Cada Thread tem associada uma prioridade que herda do processo que a criou. O Windows NT tem 32 nveis de prioridade divididos em duas classes: Prioridade Real-time - Prioridades entre 16 e 31, que so as mais alta prioridade e destinadas a threads com processamento critico em termos temporais;

DEEC - Seco de Engenharia de Sistemas

Maio, 1997

16

Modelo Computacional do Windows NT Prioridades Variveis - Prioridades entre 0 e 15. A prioridade 0 reservada para uso do sistema. O sistema ajusta a prioridade das threads com vista optimizao dos tempos de resposta. Quando um thread preempted por fim de time slice o sistema baixa a sua prioridade. Quando o thread sai do estado WAITING o sistema aumenta a sua prioridade. 3.2 Criao de threads utilizando a Win 32 API 3.2.1 Funo CreateThread
HANDLE CreateThread( LPSECURITY_ATTRIBUTES DWORD LPTHREAD_START_ROUTINE LPVOID DWORD LPDWORD ); lpThreadAttributes, dwStackSize, lpStartAddress, lpParameter, dwCreationFlags, lpThreadId

O primeiro parmetro um apontador para uma estrutura do tipo SECURITY_ATTRIBUTES permitindo a definio dos atributos de segurana associados ao thread. Se for passado o valor NULL so assumidos os atributos por omisso. O parmetro dwStackSize define a dimenso mxima do stack associado ao thread. Quando for passado zero como valor deste argumento o limite do stack de 1Mb sendo o nmero de pginas previamente atribudas (commit) especificadas no EXE. Os parmetro lpStartAddress e lpParameter definem, respectivamente, o endereo da funo que o novo thread vai executar e o argumento a ser passado a essa funo. Este argumento poder ser interpretado, pela funo, com um valor a 32 bits ou um apontador para uma estrutura de dados. O parmetro dwCreationFlags controla a criao do thread. Quando o seu valor zero, o thread comea a executar-se imediatamente a seguir sua criao, quando o valor CREATE_SUSPEND o thread criado no estado suspenso. Finalmente, atravs do ltimo parmetro devolvido o identificar atribudo pelo sistema ao novo thread. No Windows NT este parmetro nunca pode ser NULL. 3.2.2 Funo ExitThread
VOID ExitThread( DWORD dwExitCode );

Termina a execuo do thread atribudo-lhe como cdigo de terminao o valor indicado no parmetro. 3.3 Problemas existentes com a Bibliotecas do C/C++ A Microsoft fornece trs bibliotecas C (C run-time libraries): LIBC.LIB Biblioteca esttica para aplicaes em que existe apenas um thread por processo LIBCMT.LIB Biblioteca esttica para aplicaes multi-thread

DEEC - Seco de Engenharia de Sistemas

Maio, 1997

17

Modelo Computacional do Windows NT MSVCRT.LIB Biblioteca destinada ligao com a biblioteca dinmica MSVCRT20.DLL e que se destina a aplicaes com um nico thread ou multi-thread. A razo da existncia de bibliotecas distintas para aplicaes multi-thread e uni-thread reside no facto da biblioteca de C, desenvolvida nos anos 70, no ter em considerao a possibilidade de execuo num ambiente multi-tarefa. Considere, por exemplo, o que acontece com a varivel global errno. Todas as funes de acesso ao sistema, em situao de erro, indicam em errno o tipo de erro que ocorreu, assim e como a varivel global pode acontecer que dois threads executem, em simultneo, duas chamadas ao sistema o que originar efeito imprevisveis. Este apenas um exemplo, existem outras variveis e funes que oferecem o mesmo tipo de problemas, como por exemplo _doserrno, strtok, streeror, _strerror, tmpnam, tmpfile, asctime, _wasctime, gmtime, etc. Assim, para que os programas muti-tarefa escritos em C e C++, possam utilizar a biblioteca do C e trabalharem correctamente, deve ser criada e associada uma estrutura de dados a cada um dos threads criados. Esta estrutura conter, a ttulo de exemplo, um atributo a ser utilizado com varivel errno pelo thread. Este objectivo alcanado utilizando, em vez da funo CreatThread, a funo _beginthreadex. Basicamente esta funo semelhante sua congnere CreateThread havendo no entanto a necessidade de algumas coeres de tipos. 3.3.1 Funo _beginthreadex
unsigned long _beginthreadex( void * security, unsigned stack_size, unsigned ( * start_address ) (void *), void * arglist, unsigned initflag, unsigned * thrdaddr );

Como j anteriormente referido, esta funo possui os mesmo parmetro da funo CreateProcess existindo apenas algumas diferenas ao nvel do tipo dos seus parmetros. O ltimo Parmetro no pode tomar o valor NULL. A funo _beginthreadex retorna zero se ocorreu um erro ao mesmo tempo que afecta a varivel errno. Na ausncia de erros retornado o descritor do novo thread. Sobre o valor retornado pode ser realizado uma coero para o tipo utilizado pela API WIN32 - Handle. 3.3.2 Macro/funo BEGINTHREADEX A utilizao da funo _beginthreadex torna-se um pouco incomoda uma vez que os tipos dos parmetros diferem dos utilizados pela funo CreateThread e para alm disso o tipo do descritor tambm diferente obrigando a diversas coeres. Para facilitar o seu uso e tornar uniforme a utilizao de ambas as funes, _beginthreadex e CreateThread, sugerimos a utilizao da macro ou da funo, no caso da compilao em C++, BEGINTHREADEX.
#ifndef _BEGINTHREADEX_h #define _BEGINTHREADEX_h #include <windows.h> #include <process.h>

DEEC - Seco de Engenharia de Sistemas

Maio, 1997

18

Modelo Computacional do Windows NT

typedef unsigned (__stdcall *PTHREAD_START) (void *); #ifndef __cplusplus ///////////////////////////////////////////////////////////////// // Macro BEGINTHREADEX que chama a funo da biblioteca do C // _beginthreadex. No entanto esta no mantm a compatibilidade // com os tipos de dados do WIN32, por exemplo o tipo devolvido, // obrigando utilizador a fazer uma coero para HANDLE. // A macro tem como objectivo facilitar a utilizao desta funo // #define BEGINTHREADEX( lpThreadAttributes, dwStackSize, lpStartAddress, lpParameter, dwCreationFlags, lpThreadId) ((HANDLE)_beginthreadex( (void *) (lpThreadAttributes), (unsigned) (dwStackSize), (PTHREAD_START) (lpStartAddress), (void *) (lpParameter), (unsigned) (dwCreationFlags), (unsigned *) (lpThreadId))) #else ///////////////////////////////////////////////////////////////// // Esta funo tem exactamente o mesmo objectivo da macro // BEGINTHREADEX, podendo ser utilizado quando em compilao C++. // Tem como vantagem em relao macro a validao dos parmetros, // parmetros estes compativeis com os definidos para a funo // CreateThread. // inline HANDLE BEGINTHREADEX ( LPSECURITY_ATTRIBUTES lpThreadAttributes, DWORD LPTHREAD_START_ROUTINE LPVOID DWORD LPDWORD { return (HANDLE)_beginthreadex( (void *) (lpThreadAttributes), (unsigned) (dwStackSize), (PTHREAD_START) (lpStartAddress), (void *) (lpParameter), (unsigned) (dwCreationFlags), (unsigned *) (lpThreadId) ); } #endif #endif // ifndef __cplusplus // ifndef _BEGINTHREADEX Ficheiro 4 - beginthreadex.h dwStackSize, lpStartAddress, lpParameter, dwCreationFlags, lpThreadId

\ \ \ \ \ \ \

3.3.3 Funo _endthreadex


void _endthreadex( unsigned retval );

Termina a execuo do thread, criado atravs da funo _beginthreadex, atribuindo-lhe como cdigo de terminao o valor indicado no parmetro.

DEEC - Seco de Engenharia de Sistemas

Maio, 1997

19

Modelo Computacional do Windows NT

3.3.4 Funes _beginthread e _endthread A biblioteca do C contm no entanto outras duas funes:
unsigned long _beginthread( void( *start_address )( void * ), unsigned stack_size, void *arglist ); void _endthread( void );

Estas duas funes foram as predecessoras das duas novas funes _beginthreadex e _enthreadex. Como poder ser observada pelos seus prottipos so mais limitadas, no se pode por exemplo definir os atributos de segurana do novo thread e no se pode definir qual o seu valor de terminao. Estas funes existem apenas por questes de manuteno da compatibilidade com aplicaes antigas pelo que o seu uso desaconselhado devendo-se optar pelas duas funes anteriormente descritas. 3.4 Funo GetExitCodeThread
BOOL GetExitCodeThread( HANDLE hThread, LPDWORD lpExitCode );

Funo semelhante funo GetExitCodeProcess. Permite a determinao do valor de terminao de um thread. No caso deste ainda se encontrar em execuo o valor devolvido em lpExitCode STILL_ACTIVE. 3.5 Funo SuspendThread
DWORD SuspendThread( HANDLE hThread );

O thread, identificada pelo descritor passado funo, suspenso sendo incrementado um contador associados suspenso. 3.6 Funo ResumeThread
DWORD ResumeThread( HANDLE hThread );

Decrementa o contador de suspenses do thread e caso este atinja o valor nulo o thread retoma a sua execuo.

DEEC - Seco de Engenharia de Sistemas

Maio, 1997

20

Modelo Computacional do Windows NT

4. Mecanismos de sincronizao
4.1 Regies criticas (Critical Section) Para criar um regio crtica necessrio declarar uma varivel do tipo CRITICAL_SECTION. Uma vez que o objecto reside no espao de endereamento do processo, este mecanismo serve apenas como mecanismo de sincronizao entre threads pertencentes a um mesmo processo. Este mecanismo permite o estabelecimento de regies crticas no acesso a recursos garantido o acesso exclusivo de mltiplos threads. 4.1.1 Funo InitializeCriticalSection
VOID InitializeCriticalSection( LPCRITICAL_SECTION lpCriticalSection );

4.1.2 Funo DeleteCriticalSection


VOID DeleteCriticalSection( LPCRITICAL_SECTION lpCriticalSection );

4.1.3 Funo EnterCriticalSection


VOID EnterCriticalSection( LPCRITICAL_SECTION lpCriticalSection );

4.1.4 Funo LeaveCriticalSection


VOID LeaveCriticalSection( LPCRITICAL_SECTION lpCriticalSection );

4.1.5 Exemplo
#include <stdio.h> #include <windows.h> #include <beginthreadex.h> #define NUMERO_DE_CONTADORES int BOOL threads HANDLE CRITICAL_SECTION ecr ThreadNr; repeat; 6 // Numero de threads contadores // Numero de threads lanadas // Controlar a terminao dos

hConsoleOut; // Handle da consola Screen_CriticalSection; // Garantir acesso exclusivo ao

void CheckKey( void * ); void GotoXY( int, int ); void Contador( void * );

DEEC - Seco de Engenharia de Sistemas

Maio, 1997

21

Modelo Computacional do Windows NT


int main() { HANDLE handle; DWORD tid; // --- Thread Primria ---

printf("Inicio do teste dos threads utilizando Critical Section...\n"); repeat = TRUE; hConsoleOut = GetStdHandle( STD_OUTPUT_HANDLE ); // Handle da consola InitializeCriticalSection(&Screen_CriticalSection); // Inicia titulo da consola SetConsoleTitle( "TESTE DOS THREADS NO WIN95 *** SO/1997" ); handle = BEGINTHREADEX( NULL, 0, (LPTHREAD_START_ROUTINE)CheckKey, NULL, 0, &tid ); if ( handle == NULL ) { perror("ERRO NO _beginthreadex"); exit(-1); } for ( ThreadNr = 0; ThreadNr < NUMERO_DE_CONTADORES; ThreadNr++ ) { BEGINTHREADEX( NULL, 0, (LPTHREAD_START_ROUTINE)Contador, (void *)ThreadNr, 0, &tid); if ( handle == NULL ) { perror("ERRO na criao dos contadores"); exit(-1); } } while ( repeat ) ; // Todos os threads terminaram. // Fechar todos os handlers utilizados EnterCriticalSection(&Screen_CriticalSection); GotoXY(0,23); printf("Fim do teste dos threads!...\n"); DeleteCriticalSection(&Screen_CriticalSection); CloseHandle( hConsoleOut ); return 0; } // main //--------------------------------------------------------------// CheckKey - Espera que seja premido uma tecla e // coloca a flag repeat a falso // void CheckKey( void *dummy ) { _getch(); repeat = FALSE; // Fora a terminao dos Threads _endthreadex( 0 ); } // CheckKey void Contador( void *MyID ) { int conta = 0; // --- Thread Contador ---

while ( repeat ) { // Espera pela disponibilidade do ecr EnterCriticalSection(&Screen_CriticalSection); GotoXY( 6, ( (int)MyID*2+3) ); printf("Sou o thread [%d] CONT= %04d\n", (int)MyID, conta++); LeaveCriticalSection(&Screen_CriticalSection); Sleep(((int)MyID+1) * 200); } _endthreadex( 0 ); DEEC - Seco de Engenharia de Sistemas Maio, 1997 22

Modelo Computacional do Windows NT


} // Contador void GotoXY( int x, int y ) { COORD CurPos; CurPos.X = x; CurPos.Y = y; SetConsoleCursorPosition(hConsoleOut, CurPos); } // GotoXY Ficheiro 5 - ContadoresCriticalSection.cpp

4.2 Sincronizao de threads utilizando objectos do ncleo Vimos anteriormente as regies criticas como um mecanismo para garantir o acesso exclusivo a recursos por threads pertencentes ao mesmo processo. Contudo, poder ser necessria a sincronizao com outros tipos de eventos da mquina ou entre treads pertencentes a processos distintos. Os seguintes objectos do ncleo podem ser utilizados para a sincronizao entre threads independentemente dos processos a que pertencem: Processos Threads Ficheiros Input do terminal Notificaes de alteraes em ficheiros Excluso mutua (Mutexes) Semforos (Semaphores) Eventos (Events) Os threads tm disponveis duas funes que lhes permitem adormecer at que os objectos do ncleo sejam sinalizados - WaitforSingleObjects e WaitforMultipleObjects. 4.2.1 Funo WaitForSingleObjects
DWORD WaitForSingleObject( HANDLE hHandle, DWORD dwMilliseconds );

Esta funo, permite que um thread espere que o objecto identificado pelo parmetro hHandle seja sinalizado. O segundo parmetro indica o tempo (timeout), em milisegundos, que o thread est disposto a esperar. Se o objecto no for sinalizado durante o tempo indicado, o sistema acordar o thread garantindo a continuao da sua execuo. No segundo parmetro, para alm do tempo de espera, pode ser indicado dois valores especiais. O valor zero indica que no se pretende qualquer tipo de espera, mas apenas testar o estado de sinalizao do objecto. Se quisermos esperar incondicionalmente pela sinalizao podemos indicar o valor INFINITE.
DEEC - Seco de Engenharia de Sistemas Maio, 1997 23

Modelo Computacional do Windows NT A funo devolve os seguintes valores: WAIT_OBJECT_0 WAIT_ABANDONED WAIT_TIMEOUT WAIT_FAILED O objecto indicado foi sinalizado. O objecto indicado um mutex e o thread que o possua terminou sem o libertar. O objecto indicado no sinalizado durante o perodo de tempo indicado. Ocorreu um erro. Para uma descrio mais pormenorizada evocar a funo GetLastError.

4.2.2 Funo WaitForMultipleObjects


DWORD WaitForMultipleObjects( DWORD nCount, CONST HANDLE * lpHandles, BOOL bWaitAll, DWORD dwMilliseconds );

Esta funo semelhante anteriormente mencionada, WaitForSingleObjects, mas permitindo no s a espera de sinalizao de um objecto mas esperar tambm que vrios objectos sejam sinalizados. O primeiro parmetro, nCount, indica o nmero de objectos que a funo vai considerar. Este valor no pode ser superior constante MAXIMUM_WAIT_OBJECTS definida com o valor 64. O segundo parmetro, lpHandles, um apontador para um vector de descritores identificando os objectos. Os descritores indicados neste vector no podem repetir-se. O terceiro parmetro, bWaitAll, indica se a espera apenas at um dos objectos ser sinalizado (valor igual a FALSE) ou se a espera at que todos os eles estejam sinalizados ao mesmo tempo. O ltimo argumento tem o mesmo significado que o da funo WaitForSingleObject. A funo devolve os seguintes valores: WAIT_OBJECT_0 at (WAIT_OBJECT_0 + nCount 1) Se bWaitAll TRUE, o valor devolvido indica que todos os objectos indicados foram sinalizados. Se bWaitAll FALSE, o valor devolvido subtraindo do valor WAIT_OBJECT_0 representa o ndice do vector de descritores (lpHandles) correspondendo ao objecto que satisfez a condio de espera. Se mais do que um objecto estiverem sinalizados este valor o correspondente ao ndice de menor valor. WAIT_ABANDONED_0 at Se bWaitAll TRUE, O valor devolvido (WAIT_ABANDONED_0 + nCount 1) representa que todos os objectos foram sinalizados e que pelo menos um o foi, em consequncia da terminao de um thread que era
DEEC - Seco de Engenharia de Sistemas Maio, 1997 24

Modelo Computacional do Windows NT detentor de um mutex. Se bWaitAll FALSE, o valor devolvido subtrado do valor WAIT_ABANDONED_0 representa o ndice do vector de descritores (lpHandles) correspondendo a um objecto (mutex abandonado) que satisfez a condio de espera. WAIT_TIMEOUT WAIT_FAILED O objecto indicado no foi sinalizado durante o perodo de tempo indicado. Ocorreu um erro. Pode-se evocar a funo GetLastError para uma descrio mais pormenorizada.

4.3 Excluso mtua (Mutex) Os Mutex so semelhantes ao mecanismo de regio critica, excepto que permitem a sincronizao entre processos. 4.3.1 Funo CreateMutex
HANDLE CreateMutex( LPSECURITY_ATTRIBUTES BOOL LPCTSTR ); lpMutexAttributes, bInitialOwner, lpName

O parmetro lpMutexAttributes referencia uma estrutura de atributos de segurana. O segundo parmetro, bInitialOwner, se tomar o valor TRUE indica que o thread que cria o objecto mutex fica como seu dono, ou seja, outros threads que efectuem uma espera neste mecanismo vo bloquear at que este liberte o recurso. Se o valor for FALSE o mutex no pertena de nenhum dos threads. O ltimo parmetro representa o nome que vai ser associado ao objecto. Este nome constitudo por um sequncia qualquer de caracteres, excepto o caracter '\', e de dimenso mxima igual a MAX_PATH. No entanto o mutex pode ser criado sem nome, passando-se neste caso o valor NULL. Para efeitos de comparaes distinguem-se maisculas de minsculas (case sensitive). A funo devolve, em situao de falha, o valor NULL podendo ser evocada a funo GetLastError para uma melhor descrio do erro. Um dos valores devolvidos por esta funo : ERROR_INVALID_HANDLE O nome indicado no ltimo parmetro (lpName) identifica um objecto diferente de mutex. Esta situao pode ocorrer porque os objectos, eventos, mutex, semforos e mapeamento de ficheiros, partilham o mesmo espao de nomes.

Caso a funo suceda devolvido um descritor de um objecto. Nesta situao pode tambm se evocada a funo GetLastError permitindo o teste da seguinte situao:
DEEC - Seco de Engenharia de Sistemas Maio, 1997 25

Modelo Computacional do Windows NT

ERROR_ALREADY_EXISTS 4.3.2 Funo OpenMutex

Situao em que se tentou criar um mutex, com um determinado nome, e este j existia no sistema.

HANDLE OpenMutex( DWORD dwDesiredAccess, BOOL bInheritHandle, LPCTSTR lpName );

Permite a obteno de um descritor de um mutex criado atravs da funo CreateMutex com o nome indicado por lpName. O parmetro dwDesiredAccess define o acesso pretendido ao objecto mutex. Em sistemas que suportem segurana, esta funo falha se o descritor de segurana do objecto no permitir o nvel de acesso referido neste parmetro. O valor deste parmetro pode envolver qualquer combinao dos seguintes valores: MUTEX_ALL_ACCESS SYNCHRONIZE Especifica todas as flags de acesso possveis para este objecto mutex. Windows NT: Permite a utilizao do descritor em qualquer uma das funes, para aquisio do mutex ou na funo ReleaseMutex.

O parmetro bInheritHandle indica quando que o descritor devolvido pela funo herdado pelos processos filhos, criados atravs da funo CreateProcess. O ltimo parmetro identifica o mutex pretendido atravs de um nome, nome este formado segundo a regra atrs apresentada. A funo devolve um descritor do mutex na situao de ausncia de erros. Se existir um erro a funo devolve o valor NULL, podendo-se evocar a funo GetLastError para obteno de informao mais detalhada. 4.3.3 Funo ReleaseMutex
BOOL ReleaseMutex( HANDLE hMutex );

Liberta a posse do objecto mutex indicando o handler previamente obtido por uma das duas funes anteriores. Para libertar um mutex, o thread dever evocar esta funo tantas vezes quantos o nmero de vezes que evocou um das funes de espera (WaitForSingleObject e WaitForMultipleObjects). Isto porque enquanto um thread possuir um mutex, este pode evocar uma das funes wait para o mesmo mutex, sem se bloquear de modo a evitar situaes de deadlock. Note que se um thread, na posse de um mutex, terminar sem evocar esta funo, ele ir provocar que nenhum dos outros thread, adormecidos espera que o mutex seja libertado, sejam acordados. O sistema, quando detecta esta situao, sinaliza automaticamente os threads, sendo nesta situao, devolvido pelas funes de espera o valor WAIT_ABANDONED.

DEEC - Seco de Engenharia de Sistemas

Maio, 1997

26

Modelo Computacional do Windows NT 4.3.4 Exemplo Vamos rescrever o exemplo das regies criticas utilizando os mutex.
#include #include #include #include #include <conio.h> <process.h> <stdio.h> <windows.h> <beginthreadex.h> 6 // Numero de threads contadores // // // // Numero de threads lanadas Controlar a terminao dos threads Handle da consola Mutex para actualizacao da consola

#define NUMERO_DE_CONTADORES int BOOL HANDLE HANDLE ThreadNr; repeat; hConsoleOut; hScreenMutex;

void CheckKey( void * ); void GotoXY( int, int ); void Contador( void * ); int main() // --- Thread Primria --{ HANDLE handle; HANDLE THandlers[NUMERO_DE_CONTADORES]; DWORD tid; printf("Inicio do teste dos threads utilizando Mutex...\n"); repeat = TRUE; hConsoleOut = GetStdHandle( STD_OUTPUT_HANDLE ); // Handle da consola hScreenMutex = CreateMutex( NULL, FALSE, NULL ); // Valor inicial = 1 // Inicia titulo da consola SetConsoleTitle( "TESTE DOS THREADS NO WIN95 *** SO/1997" ); handle = BEGINTHREADEX( NULL, 0, (LPTHREAD_START_ROUTINE)CheckKey, NULL, 0, &tid ); if ( handle == NULL ) { perror("ERRO NO _beginthreadex"); exit(-1); } for ( ThreadNr = 0; ThreadNr < NUMERO_DE_CONTADORES; ThreadNr++ ) { THandlers[ThreadNr]=BEGINTHREADEX( NULL, 0, (LPTHREAD_START_ROUTINE)Contador, (LPVOID)ThreadNr, 0, &tid ); if ( THandlers[ThreadNr] == NULL ) { perror("ERRO na criao dos contadores"); exit(-1); } } // Espera que todos os threads contadores terminem WaitForMultipleObjects(ThreadNr, THandlers, TRUE, INFINITE); // Todos os threads terminaram. // Fechar todos os handlers utilizados GotoXY(0,23); printf("Fim do teste dos threads!...\n"); CloseHandle( hScreenMutex ); CloseHandle( hConsoleOut ); return 0; } // main

DEEC - Seco de Engenharia de Sistemas

Maio, 1997

27

Modelo Computacional do Windows NT

//--------------------------------------------------------------// CheckKey - Espera que seja premido uma tecla e // coloca a flag repeat a falso // void CheckKey( void *dummy ) { _getch(); repeat = FALSE; /* Fora a terminao dos Threads */ _endthreadex( 0 ); } /* CheckKey */ void Contador( void *MyID ) { int conta = 0; // --- Thread Contador ---

while ( repeat ) { /* Espera pela disponibilidade do ecr */ WaitForSingleObject( hScreenMutex, INFINITE ); GotoXY( 6, ( (int)MyID*2+3) ); printf("Sou o thread [%d] CONT= %04d\n", (int)MyID, conta++); ReleaseMutex( hScreenMutex ); Sleep(((int)MyID+1) * 200); } _endthreadex( 0 ); } /* Contador */ void GotoXY( int x, int y ) { COORD CurPos; CurPos.X = x; CurPos.Y = y; SetConsoleCursorPosition(hConsoleOut, CurPos); } /* GotoXY */ Ficheiro 6 - ContadoresMutex.cpp

4.4 Semforos (Semaphores)


Os semforos so utilizados como contadores de recursos. Considere o exemplo de um computador com trs portas srie onde um conjunto de threads as utilizem para comunicao. Esta situao oferece uma boa oportunidade utilizao de um semforo com valor inicial 3, ou seja, o semforo apenas admite trs threads a aceder aos portos.

4.4.1 Funo CreateSemaphore


HANDLE CreateSemaphore( LPSECURITY_ATTRIBUTES LONG LONG LPCTSTR ); lpSemaphoreAttributes, lInitialCount, lMaximumCount, lpName

A funo CreateSemaphore permite a criao de um objecto semforo associando-lhe ou no um nome. assim possvel a sua utilizao entre processos.

DEEC - Seco de Engenharia de Sistemas

Maio, 1997

28

Modelo Computacional do Windows NT O parmetro lpSemaphoreAttributes referncia uma estrutura com os atributos de segurana a serem associados ao objecto. Se for indicado o valor NULL o objecto semforo criado com um descritor por omisso. O parmetro lInitialCount indica o valor inicial do semforo. Este valor dever ser um valor superior ou igual a zero e inferior ou igual constante IMaximumCount. O terceiro parmetro lMaximumCount indica o mximo valor que o semforo pode tomar. Este valor tem de ser superior a zero O ltimo parmetro permite indicar um nome a associar a este objecto. A regra de formao do nome idntica dos mutex, uma vez que partilham o mesmo espao de nomes. O valor devolvido pela funo tem a mesma semntica da sua congnere dos mutex. 4.4.2 Funo OpenSemaphore
HANDLE OpenSemaphore( DWORD dwDesiredAccess, BOOL bInheritHandle, LPCTSTR lpName );

Esta funo permite a obteno de um descritor de um semforo, previamente criado com um nome associado. O primeiro parmetro especifica define o acesso pretendido ao objecto e pode tomar qualquer combinao dos seguintes valores: SEMAPHORE_ALL_ACCESS SEMAPHORE_MODIFY_STATE SYNCHRONIZE Especifica todas as possveis flags de acesso ao objecto. Permite a utilizao do descritor do semforo da funo ReleaseSemaphore. Windows NT: Permite a utilizao do descritor em qualquer uma das funes para aquisio do semforo.

Os restantes dois parmetros, assim com o valor devolvido so semelhantes da funo congnere dos mutex OpenMutex. 4.4.3 Funo ReleaseSemaphore
BOOL ReleaseSemaphore( HANDLE hSemaphore, LONG lReleaseCount, LPLONG lpPreviousCount );

A funo ReleaseSemaphore adiciona ao contador do semforo indicado o valor passado no segundo argumento, lReleaseCount. Este valor dever ser superior a zero. No caso do valor do semforo exceder o mximo valor permitido para o semforo, o seu contador no alterado e a funo devolve FALSE. O ltimo parmetro permite receber o valor anterior do respectivo semforo. Caso este valor no seja necessrio pode ser passado com o valor NULL. Os semforos no oferecem qualquer mecanismo que permita a leitura do valor actual do semforo sem a alterao do seu valor.
DEEC - Seco de Engenharia de Sistemas Maio, 1997 29

Modelo Computacional do Windows NT 4.4.4 Exemplo Pretende-se um programa para simular a visita ao interior da pirmide do Fara Egpcio. A cmara onde se encontra o tmulo do Fara, por razes de segurana e capacidade de ventilao s pode comportar no mximo cinco visitantes. Por seu turno o acesso cmara feito por um corredor muito estreito onde s cabe uma pessoa de cada vez (tanto para entrar como para sair). Pretende-se uma estratgia que discipline o acesso dos visitantes ao tmulo, fazendo com que os visitantes em excesso esperem pela sua vez entrada da pirmide. Note-se que os tempos de visita por visitante no so determinsticos, bem como o tempo que estes demoram a atravessar o corredor de acesso.
#include #include #include #include #include <conio.h> <process.h> <stdio.h> <windows.h> <beginthreadex.h> 22 // Numero de visitantes da simulao 5 // Mximo de visitantes no tmulo

#define NUMERO_VISITANTES #define MAX_VISITANTES

// // getrandom devolve um nmero aleatrio entre o intervalo min and max // #define getrandom(min, max) ((rand() % (int)(((max) + 1) - (min))) + (min)) #define AtravessarCorredor() Sleep( getrandom( 100, 400 ) ) #define VisitarCamara() Sleep( getrandom( 2000, 5000 ) ) CRITICAL_SECTION Screen_CriticalSection; // Garantir acesso exclusivo ao ecr HANDLE hCorredorMutex; // Acesso exclusivo ao corredor HANDLE hEntradaMutex; // Indica se a pirmide esta aberta para visitas HANDLE hLugaresTumoloSem; // Contolo do n de visitantes no tmulo HANDLE hConsoleOut; // Handle da consola BOOL repeat; // Controlar a terminao dos threads int visitantes_camara; // Numero de visitantes na cmara do Fara void void void void void visitante ( LPVOID vid ); // simula um visitante CheckKey( void * ); EscreveStatus( const char *, int ); RefreshConsoleTitle( ); GotoXY( int, int ); ) ThreadNr; THandlers[NUMERO_VISITANTES]; tid;

int main ( { int HANDLE DWORD

printf("Visita ao templo do Farao...\n"); visitantes_camara = 0; repeat = TRUE; // Inicia titulo da consola RefreshConsoleTitle( ); InitializeCriticalSection(&Screen_CriticalSection); hConsoleOut = GetStdHandle( STD_OUTPUT_HANDLE ); hCorredorMutex = CreateMutex( NULL, FALSE, NULL ); //Valor inicial=1 DEEC - Seco de Engenharia de Sistemas Maio, 1997 30

Modelo Computacional do Windows NT


hEntradaMutex = CreateMutex( NULL, FALSE, NULL ); hLugaresTumoloSem = CreateSemaphore( NULL, MAX_VISITANTES, MAX_VISITANTES, NULL ); BEGINTHREADEX( NULL, 0, (LPTHREAD_START_ROUTINE)CheckKey, NULL, 0, &tid ); for ( ThreadNr = 0; ThreadNr < NUMERO_VISITANTES; ThreadNr++ ) { THandlers[ThreadNr] = BEGINTHREADEX( NULL, 0, (LPTHREAD_START_ROUTINE)visitante, (LPVOID)ThreadNr, 0, &tid ); } // Espera que todos os threads contadores terminem WaitForMultipleObjects(ThreadNr, THandlers, TRUE, INFINITE); GotoXY(0,24); printf("Fim da visita ao templo do Farao!..."); // Todos os threads terminaram. // Fechar todos os handlers utilizados DeleteCriticalSection(&Screen_CriticalSection); CloseHandle( hConsoleOut ); CloseHandle( hCorredorMutex ); CloseHandle( hEntradaMutex ); CloseHandle( hLugaresTumoloSem ); return 0; } // main void visitante ( LPVOID vid ) { while ( repeat ) { WaitForSingleObject( hLugaresTumoloSem, INFINITE ); // Esperar vez para visitar o templo do Fara EscreveStatus("Espera corredor livre para entrar", (int)vid); WaitForSingleObject( hCorredorMutex, INFINITE ); // Atravessa o corredor para visitar a cmara EscreveStatus("Atravessa corredor para entrar", (int)vid); AtravessarCorredor(); ReleaseMutex( hCorredorMutex ); // Visita a cmara do Fara visitantes_camara++; RefreshConsoleTitle(); EscreveStatus("Visitando a camara do Farao", (int)vid); VisitarCamara(); // Terminou a visita e espera vez para atravessar o corredor EscreveStatus("Espera corredor livre para sair", (int)vid); WaitForSingleObject( hCorredorMutex, INFINITE ); // Atravessa o corredor para sair EscreveStatus("Atravessa corredor para sair", (int)vid); AtravessarCorredor(); ReleaseMutex( hCorredorMutex ); visitantes_camara--; RefreshConsoleTitle(); // D a vez a outro visitante EscreveStatus("Espera a sua vez para nova visita", (int)vid); ReleaseSemaphore( hLugaresTumoloSem, 1, NULL ); } EscreveStatus("Foi para casa.", (int)vid); _endthreadex( 0 ); } // visitante

DEEC - Seco de Engenharia de Sistemas

Maio, 1997

31

Modelo Computacional do Windows NT


//--------------------------------------------------------------// CheckKey - Espera que seja premido uma tecla e // coloca a flag repeat a falso // void CheckKey( void *dummy ) { _getch(); repeat = FALSE; /* Fora a terminao dos Threads */ RefreshConsoleTitle(); _endthreadex( 0 ); } // CheckKey //--------------------------------------------------------------// Escreve a mensagem indicada em str na coluna respectiva do // visitante identificado no segundo parmetro // void EscreveStatus( const char * str, int visitante ) { EnterCriticalSection(&Screen_CriticalSection); GotoXY( 6, visitante + 2 ); printf("%02d - %-50s", visitante, str); LeaveCriticalSection(&Screen_CriticalSection); } // EscreveStatus void RefreshConsoleTitle( ) { char Msg[280]; int i; i=sprintf(Msg," Pirmide do Fara Egipcio **Templo " ); if ( repeat ) i += sprintf(Msg+i, "Aberto** n visitantes na cmara " ); else i += sprintf(Msg+i, "fechado** n visitantes na cmara " ); sprintf( Msg + i, "%d", visitantes_camara ); SetConsoleTitle( Msg ); } // RefreshConsoleTitle void GotoXY( int x, int y ) { COORD CurPos; CurPos.X = x; CurPos.Y = y; SetConsoleCursorPosition(hConsoleOut, CurPos); } // GotoXY Ficheiro 7 - Farao.cpp

4.5 Eventos (Events) Os eventos so um mecanismo bsico de sincronizao. Enquanto os mutex e semforos so normalmente usados para controlar o acesso a dados, os eventos so usados para sinalizar o fim de uma operao. Consideremos uma aplicao em que um thread faz iniciaes aps a quais outros threads podem iniciar a sua execuo. O thread que faz as iniciaes coloca um evento no estado no sinalizado (no aconteceu). Os threads que fazem o seu trabalho aps as

DEEC - Seco de Engenharia de Sistemas

Maio, 1997

32

Modelo Computacional do Windows NT iniciaes suspendem-se no evento at que o thread de iniciaes coloque o evento no estado sinalizado. Existem dois tipos de eventos. Os eventos manual-reset que servem para sincronizar com vrios threads em simultneo. Por exemplo no caso anterior todas as threads seriam acordadas quando o thread de iniciao sinalizasse o evento. Os eventos auto-reset servem para sinalizar um nico thread que uma operao foi concluda. 4.5.1 Funo CreateEvent
HANDLE CreateEvent( LPSECURITY_ATTRIBUTES BOOL BOOL LPCTSTR ); lpEventAttributes, bManualReset, bInitialState, lpName

O parmetro bManualReset indica ao sistema se pretendemos criar um evento manual (TRUE) ou automtico (FALSE). O parmetro bInitialState indica se o evento deve ser iniciado no estado sinalizado (TRUE) ou no sinalizado (FALSE). Os restantes dois parmetros tem a mesma semntica das outras funes dos semforos e mutex. 4.5.2 Funo OpenEvent
HANDLE OpenEvent( DWORD dwDesiredAccess, BOOL bInheritHandle, LPCTSTR lpName );

Funo que permite a obteno de um descritor para um evento previamente criado. 4.5.3 Funo SetEvent
BOOL SetEvent( HANDLE hEvent );

Permite sinalizar um evento, desbloqueando os threads que eventualmente estejam em WaitForSingleObject ou WaitForMultipleObject sobre o handle do objecto hEvent. 4.5.4 Funo ResetEvent
BOOL ResetEvent( HANDLE hEvent );

Coloca um evento no estado no sinalizado. 4.5.5 Funo PulseEvent


BOOL PulseEvent( HANDLE hEvent );

Permite fazer SetEvent e ResetEvent de forma atmica.

DEEC - Seco de Engenharia de Sistemas

Maio, 1997

33

Modelo Computacional do Windows NT 4.6 Famlia de funes Interlocked Este conjunto de funes tem como nico objectivo a alterao, de forma atmica, do valor de um inteiro longo. A atomicidade garantida qualquer que seja o nmero de processadores existentes no sistema. A forma normal de garantir a actualizao atmica de um inteiro longo recorrendo utilizao regies criticas ou de mutex. No entanto, sendo esta operao to comum e til a Microsoft decidiu adicionar estas trs funes API WIN32. Este conjunto de funes permitem, o incremento, decremento e a afectao de uma varivel do tipo inteiro longo.
LONG InterlockedIncrement( LPLONG lpAddend ); LONG InterlockedDecrement( LPLONG lpAddend ); LONG InterlockedExchange( LPLONG Target, LONG

Value );

As funes devolvem o resultado da comparao do novo valor, do inteiro longo, com o valor zero, isto , devolve um valor negativo se o novo valor for inferior a zero, um valor positivo caso seja superior ao valor zero e devolve o valor zero quando o novo valor nulo.

5. Comunicao entre processos


Durante o desenho da aplicao devero ser identificadas as vrias tarefas a realizar assim como aquelas que so concorrentes. Estas tarefas podem ser realizadas atravs de threads diferentes pertencentes a um mesmo processo ou se a tarefa demasiada complexa, exigindo mltiplos threads para a sua realizao, recorrer criao a um novo processo filho. Nesta situao cada um dos processos possui o seu prprio espao de endereamento existindo a necessidade, de dois ou mais processos, trocarem dados entre si. A interface de programao WIN32 coloca disponvel vrios mecanismos para alcanar este objectivo, entre outros destaca-se o Dynamic Data Exchange (DDE), Object Linking Embedding (OLE), Pipes, MailSlots e ficheiros mapeados em memria.

DEEC - Seco de Engenharia de Sistemas

Maio, 1997

34

Modelo Computacional do Windows NT

6. Bibliografia

1. Ritcher, Jeffrey Advanced Windows - The developer's Guide to the Win32 API for Windows NT 3.5 and Windows 95, Microsoft Press, 1995. 2. King, Adrian, Inside Windows 95, Microsoft Press, 1994. 3. Platt, David S., Windows 95 and NT, Win32 API from Scratch A Programmer's Workbook, Prentice Hall, 4. Custer, Helen, Inside Windows NT, Microsoft Press, 1993. 5. Custer, Helen, Inside Windows NT File System, Microsoft Press, 1993. 6. Gregory, Kate, Using Visual C++ 4.2 - The Most Complete Reference, Que Corporation, 1996. 7. Visual C++ Books on line, Microsoft Developer Studio, Microsoft Visual C++ 4.00, 1995.

DEEC - Seco de Engenharia de Sistemas

Maio, 1997

35

Modelo Computacional do Windows NT

7. ANEXO A - Guia de utilizao bsica do ambiente Visual C++


Esta ferramenta de desenvolvimento semelhante s suas congneres da Borland. O ambiente constitudo por um editor de texto, compilador, debugger, ferramenta de apoio ao desenvolvimento de aplicaes orientadas por objectos, como por exemplo visualizao grfica da hierarquia de classes, dos atributos e mtodos de cada classe, permitindo tambm, atravs da referida interface grfica, uma fcil manuteno da definio dos objectos. Por ltimo existe a possibilidade de acesso aos manuais electrnicos, permitindo uma rpida consulta sobre determinado tpico. O acesso aos manuais exige a escolha, durante a instalao, da opo customize seguido da instalao dos manuais em disco, opo que custa cerca de 90 megabytes. Caso contrrio necessrio possuir o CD.

DEEC - Seco de Engenharia de Sistemas

Maio, 1997

36

Modelo Computacional do Windows NT

7.1 Iniciar um novo projecto Entrar no ambiente de desenvolvimento Microsoft Developer Studio A partir do menu de expanso vertical file seleccionar a opo new aparecendo a seguinte janela: Seleccionar Project Workspace e carregar em OK

Carregar em OK aparecendo ento a janela relativa ao novo espao de trabalho.

Escreva o nome do seu projecto na caixa Name, confirme onde este ir residir em disco na caixa location.e seleccione o tipo de projecto pretendido (no exemplo uma aplicao em modo de consola). Termine a iniciao do novo projecto carregando na tecla Create. Aps estas operaes obtivemos um novo projecto vazio. A janela da esquerda (assinalada na figura) composta por vrias pastas. Uma delas - files view, mostra-nos os ficheiros que constituiem o projecto e outra permite-nos visualizar as classes existentes no projecto. Vamos de seguida criar o primeiro ficheiro do projecto atravs do menu de espao vertical File e opo New. Selecciona-se o text file e escrevemos o nosso pequeno exemplo. Gravamos este ficheiro atravs do mtodo normal (File - Save). Falta agora associar este novo ficheiro ao nosso projecto. Para isto devemos derigir ao menu Insert e seleccionar a opo Files into Project. Finalmente podemos compilar o nosso projecto atravs do menu de expanso vertical. O resultado da compilao apresentado na janela de baixo do ambiente integrado.

DEEC - Seco de Engenharia de Sistemas

Maio, 1997

37

Modelo Computacional do Windows NT

classe view files view

Resultados da compilao

Utilizando, tambm o menu Build podemos atravs da opo Execute teste.exe executar o nosso programa. Tratando-se de uma aplicao em modo console temos o seguinte output.

Vamos agora adicionar duas definies de classes ao nosso exemplo. Definimos uma classe Base e a sua especializao Derivada, como se pode observar na figura seguinte. Depois de compilar, o projecto, a janela relativa visualizao de classes do projecto contm toda a informao relativa s classes definidas (ver figura seguinte).
DEEC - Seco de Engenharia de Sistemas Maio, 1997 38

Modelo Computacional do Windows NT

DEEC - Seco de Engenharia de Sistemas

Maio, 1997

39

Modelo Computacional do Windows NT Para acedermos a outro tipo de informao mais detalhada, sobre as classes, posicionamos o apontador do rato sobre o nome das classes e carregamos no boto direito do rato, aparecendo o menu da figura seguinte.

Se por exemplo estivermos sobre a classe Base escolhermos a opo Derived Classes surgir um janela contendo toda a informao respeitante hierarquia de classes encimada pela classe Base.

DEEC - Seco de Engenharia de Sistemas

Maio, 1997

40