Introdução à Threads para Windows na linguagem C Modularizando Threads em uma struct C Luiz Carlos d´Oleron [email protected] Introdução • Nesta aula aprenderemos: − Como usar Threads na Linguagem C; − Como criar um conjunto de artefatos que ocultem a complexidade do Sistema Operacional para programação multi-thread em C. Motivação • Gerenciamento de Threads e Processos é algo intrissecamente ligado ao Sistema Operacional • Programas que utilizam técnicas Multi-Thread podem ter código nativo do SO espalhado e misturado com outros tipos de código (negócio, persistência, etc…) • API de SO´s não são muito legíveis Exemplo • Excemplo1.c Modularizando o código • Nas linguagens Orientadas a Objetos, tal como Java e C++, existem Classes que encapsulam as responsabilidades do Thread e do Sistema Operacional • Essas Classes permitem Reuso, ao passo que podem ser Estendidas • Em C, as coisas são um pouco mais difíceis, pois não possuímos algumas ferramentas valiosas, como Herança e Polimorfismo! Classe Thread de Java Dando uma olhada na classe Thread de Java: http://java.sun.com/j2se/1.5.0/docs/api /java/lang/Thread.html Modularizando o código • A idéia principal é criar uma struct em C que, junto com algumas funções, se pareça um pouco com a classe Thread de java • Dessa forma, poderemos reutilizar a struct em nossas aplicações, ocultando nela os detalhes do Sistema Operacional • Como? A struct Thread typedef struct thread{ //um identificador para o Thread char* nome; //a funcao que deverá ser executada pelo Thread EnderecoFuncao* run; //um manipulador para o Thread //Utilizado, por exemplo, para saber se o Thread //ainda está vivo HANDLE handle; } Thread; Funções para a struct //Construtor do Thread Thread* newThread(char* nome, EnderecoFuncao* funcaoThread); //funcao start inicia a execução do Thread em //paralelo com a execução atual void start(Thread* t, void* parametros); Funções para a struct //funcao faz o Thread atual dormir por no //mínimo tempoEmMiliSegundos void sleep(int tempoEmMiliSegundos); //Faz a Thread atual aguardar pela conclusão do // Thread t void join(Thread* t); //Faz o Thread atual abdicar pela sua parcela atual // de tempo na CPU void yield(); Ops!!! • Mais na classe Thread de java, run é um método, e não um atributo! Explicando • Em C, não há Herança. Para solucionar isso, usaremos algo que não é possível ser feito em java • Definimos um Ponteiro para uma Função • Assim nossa Thread em C poderá ser extensível, mesmo sem herança Usando a struct Thread void funcaoSoma (void* param){ int i = 0; char* nome = (char*) param; for(i = 0;i<10;i++){ printf("%s : %d \n",nome,i); yield(); } } void funcaoSub (void* param){ int i = 0; char* nome = (char*) param; for(i = 9;i>=0;i--){ printf("%s : %d \n",nome,i); yield(); } } Usando a struct Thread int main(int argc, char *argv[]) { Thread* t1 = newThread(“ThreadSoma", funcaoSoma ); Thread* t2 = newThread(“ThreadSub", funcaoSub ); start(t1, t1->nome); start(t2, t2->nome); join(t1);//Aguarda t1 join(t2);//Aguarda t2 system("PAUSE"); } Exemplo com struct Thread • O mesmo exemplo do slide 4 pode ser encontrado no Exemplo2.c, dessa vez, usando a struct Thread A implementação • A implementação das funções de Thread.h podem ser encontradas na classe Thread.c • Lá estão isolados os detalhes do acesso ao Sistema Operacional A implementação • Foram utilizadas as seguintes funções da API do Windows: − CreateThread − GetExitCodeThread − Sleep A função CreateThread • Cria uma Thread para executar em paralelo no processo que a chamou; • http://msdn.microsoft.com/library/default.asp?url=/library/enus/dllproc/base/createthread.asp HANDLE CreateThread( LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId ); A função CreateThread • Exemplo de chamada de CreateThread: void funcao(void* p){...} ... char* parametros = “teste”; HANDLE handle = CreateThread(NULL,0, funcao, parametros,0,NULL); A função CreateThread • Para simplificar, daremos ênfase apenas aos parâmetros: − lpStartAddress – a função que será executada pelo Thread − lpParameter – Parâmetro que será passado para a função do Thread A função GetExitCodeThread • Retorna o código de saída da Thread, usada para descobrir se o Thread já acabou de executar sua função; • http://msdn.microsoft.com/library/default.asp?url=/library/enus/dllproc/base/getexitcodethread.asp BOOL GetExitCodeThread( HANDLE hThread, LPDWORD lpExitCode ); A função GetExitCodeThread • Exemplo de uso de GetExitCodeThread: HANDLE handle = …; LPDWORD exitCode; GetExitCodeThread(handle,&exitCode); if(exitCode==STILL_ACTIVE){ printf(“Thread ainda Funcionando”); }else{ printf(“Thread Morto”); } A função GetExitCodeThread • hThread– O “manipulador” da Thread. Componente que permite obter informações do ciclo de vida da Thread • lpExitCode– Parâmetro que contém o código de saída do Thread. Se o Thread ainda estiver executando, lpExitCode será igual a STILL_ACTIVE A função Sleep • Similar ao método estático sleep da classe Java, a função Sleep fará a Thread atual adormecer por, no mínimo, o tempo especificado; • http://msdn.microsoft.com/library/default.asp?url=/l ibrary/en-us/dllproc/base/sleep.asp VOID Sleep( DWORD dwMilliseconds ); A função Sleep • Passar o valor zero para Sleep faz com que o Thread atual abdique de seu tempo na CPU, deixando para o SO decidir por um novo Thread a executar. Se nenhum outro Thread estiver disponível, a função retorna automaticamente, fazendo com que o Thread inicial volte à exeução; • Usamos Sleep(0) para simular a função void yield(). A função Sleep • Exemplo de uso de Sleep int tempo = 10000; printf(“Fazendo o programa parar por no mínimo %d milisegundos\n”, tempo); Sleep(tempo); printf(“O programa parou por no mínimo %d milisegundos\n”, tempo); Resumo • Código que usar Thread em C irá depender do Sistema Operacional • Podemos usar structs e funções para modularizar e abstrair o código dependente do Sistema Operacional • Assim o restante do código ficará mais limpo e flexível Mais informações • Muita coisa sobre Threads não foram vistas nessa aula • O exemplo apresentado poderá ser estendido, por exemplo, para contemplar sincronização e prioridades • Procure mais informações nas fontes: − http://msdn.microsoft.com/library/default.asp?url =/library/en-us/dllproc/base/multiple_threads.asp − http://www.cin.ufpe.br/~adsl/cursos