Evitando conflitos em aplicaes multi-thread no Delphi/Kylix Edmilson dos Santos de Jesus Salvador, maro de 2002. UNIVERSIDADE DO ESTADO DA BAHIA UNEB Laboratrio de Orientao a Objetos OOLAB http://www.uneb.net/oolab - 1 - NDICE Agradecimentos................................................................ ................................ ................................ ............ 2 Aplicaes multi-thread................................................................ ................................ ................................ 3 Evitando conflitos com mltiplas threads ................................................................ ................................ ...... 5 Utilizando a Thread Principal atravs do mtodo Synchronize................................................................ ...... 6 Usando o Lock de Objetos ................................................................ ................................ ............................ 7 Protegendo sees crticas atravs da classe TCriticalSection ................................................................ ........ 7 Utilizando mltipla leitura e exclusiva escrita................................. ................................ ............................... 8 Concluses ................................................................ ................................ ................................ ................. 10 Bibliografia ................................................................ ................................ ................................ ................ 11 Autor................................................................ ................................ ................................ .......................... 12 UNIVERSIDADE DO ESTADO DA BAHIA UNEB Laboratrio de Orientao a Objetos OOLAB http://www.uneb.net/oolab - 2 - Agradecimentos Quero agradecer a todos que contriburam direta e indiretamente na elaborao desse artigo. Aos colegas do OOLAB (Laboratrio de Orientao a Objetos UNEB ), pela fora que me deram, ao Mestre Jorge Farias pela orientao, a Borland por ter feito um Help to preciso para o Kylix e o Delphi, a Andrew S. Tanenbaum, por ser to claro e direto no livro Sistemas Operacionais Modernos. Os obstculos existem para que sejam vencidos. E afinal o que seria da vida sem os obstculos? UNIVERSIDADE DO ESTADO DA BAHIA UNEB Laboratrio de Orientao a Objetos OOLAB http://www.uneb.net/oolab - 3 - Aplicaes multi-thread Aplicaes Multi-thread so aplicaes que incluem vrias linhas simultneas de execuo. Com somente uma thread a aplicao deve parar sua execuo quando estiver esperando por um processo lento tal como leitura de disco, comunicao com outra mquina, ou exibio de contedo multimdia. Com mltiplas threads a mesma aplicao pode continuar executando as outras threads enquanto a thread lenta espera pelo resultado de um processo. Para construir aplicaes multi-thread no Delphi/Kylix voc deve criar uma nova classe descendente de TThread, e cada instncia dessa nova classe ser uma linha de execuo que alocar tempo de CPU para o seu processamento. Para criar uma nova classe descendente de TThread selecione no menu principal do Delphi File | New, ou no caso do Kylix File | New | Other, na caixa de dilogo que aparece selecione Thread Object, dever aparecer uma janela para voc colocar o nome da classe que ser criada. Depois que voc colocar o nome, o Delphi/Kylix automaticamente criar uma nova unit para a implementao da thread. UNIVERSIDADE DO ESTADO DA BAHIA UNEB Laboratrio de Orientao a Objetos OOLAB http://www.uneb.net/oolab - 4 - Veja o exemplo abaixo, o corpo da unit gerada pelo Delphi para a classe TThreadTeste. Depois disso voc pode colocar o cdigo que a thread executar no mtodo Execute. Para utilizar a classe criada em outras units basta acrescentar o nome da unit na clausula uses das outras units, e pode usar classe que voc criou. Veja abaixo o exemplo do uso da classe TThreadTeste. unit UnitPrincipal; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, Unit1; type TFormPrincipal = class(TForm) ButtonCriarThread: TButton; procedure ButtonCriarThreadClick(Sender: TObject); UNIVERSIDADE DO ESTADO DA BAHIA UNEB Laboratrio de Orientao a Objetos OOLAB http://www.uneb.net/oolab - 5 - private { Private declarations } public { Public declarations } end; var FormPrincipal: TFormPrincipal; Teste:TThreadTeste; //aqui declaramos a varivel Teste do tipo TThreadTeste implementation {$R *.dfm} procedure TFormPrincipal.ButtonCriarThreadClick(Sender: TObject); begin Teste:=TThreadTeste.Create(False); //Aqui instanciamos a nova thread end; end. Evitando conflitos com mltiplas threads Quando usamos objetos da VCL e da CLX em uma aplicao multi-thread, no temos garantia de que os mtodos e propriedades desses objetos sero acessados apenas por uma thread de cada vez, o cdigo da aplicao que deve garantir isso. Esses mtodos e propriedades podem executar aes sobre a memria a qual no est protegida da ao de outras threads. Vamos supor que temos uma aplicao onde vrias threads acessam a mesma lista para inserir ou remover itens da mesma, obvio que duas thread no podem inserir ou remover itens da lista ao mesmo tempo, se isso ocorrer podem acontecer erros inesperados, ou pior, pode no ocorrer erro algum e o programa no funcionar corretamente, nesse caso o resultado final do processamento depender de quem executou quando, isso chamado de condio de corrida. Para evitar conflitos, as threads devem acessar os objetos de forma sincronizada. A maioria dos mtodos que acessam objetos da VCL ou da CLX e atualizam os formulrios devem ser chamados somente pela thread principal ou utilizando um objeto de sincronizao tal como os objetos instanciados a partir das classes TMultiReadExclusiveWriteSynchronizer ou TCriticalSection. UNIVERSIDADE DO ESTADO DA BAHIA UNEB Laboratrio de Orientao a Objetos OOLAB http://www.uneb.net/oolab - 6 - Utilizando a Thread Principal atravs do mtodo Synchronize Se voc acessa os mtodos e propriedades dos objetos a partir de uma nica thread voc no precisa se preocupar com erros causados por acesso simultneo, como valores lidos incorretamente ou violao de acesso. Para fazer com que um mtodo de outra thread use a thread principal para executar uma ao, voc deve utilizar o mtodo Synchronize. Para fazer isso crie uma rotina separada que executa a ao desejada, e depois chame-a de dentro da thread utilizando o mtodo Synchronize e passando como parmetro o nome da rotina que voc criou, veja o exemplo abaixo. Synchronize causa uma chamada especfica ao mtodo passado como parmetro utilizando a thread principal, evitando conflitos entre as threads. Synchronize espera a thread principal entrar na mensagem de loop e ento executa o mtodo passado como parmetro. OBS: Porque o mtodo Synchronize utiliza a mensagem de loop ele no pode ser utilizado em uma aplicao console. Voc deve utilizar outros mecanismos, tal como seo crtica, para proteger o acesso a objetos em aplicaes console. Evite na medida do possvel o uso de Synchronize, isso dever aumentar a performance da sua aplicao pois muitas vezes voc no precisa esperar a thread principal entrar na mensagem de loop para executar o mtodo de outra thread. UNIVERSIDADE DO ESTADO DA BAHIA UNEB Laboratrio de Orientao a Objetos OOLAB http://www.uneb.net/oolab - 7 - Usando o Lock de Objetos Alguns objetos tem proteo prpria para evitar que mais de uma thread utilize a instncia desses objetos ao mesmo tempo. Por exemplo o TCanvas tem o mtodo Lock que evita que outras threads acessem o canvas at que o mtodo Unlock seja chamado. Voc deve proteger o Canvas com um Lock em todas as chamadas que o utilizam e depois voc deve chamar o mtodo Unlock para liber-lo para outras threads. Quando o mtodo Lock chamado ele verifica se o Canvas j est bloqueado e se estiver Lock espera at que o Canvas seja liberado atravs da chamada ao mtodo Unlock pela mesma thread que o bloqueou. Protegendo sees crticas atravs da classe TCriticalSection Se um objeto no possui mtodo prprio para proteo voc pode utilizar a classe TCriticalSection para proteger uma seo crtica. UNIVERSIDADE DO ESTADO DA BAHIA UNEB Laboratrio de Orientao a Objetos OOLAB http://www.uneb.net/oolab - 8 - Seo crtica uma parte do programa cujo processamento pode levar ocorrncia de condies de corrida. Para utilizar seo crtica voc deve criar uma instncia global da classe TCriticalSection, acrescentando na clusula uses a unit StdCtrls. TCriticalSection tem dois mtodos, Acquire (que impede que as outras threads entrem na seo) e Release (que remove o bloqueio). Utilizando mltipla leitura e exclusiva escrita. Existe uma situao especial onde muitas threads precisam ler o valor de determinada regio de memria e que raramente uma thread escreve nessa regio, nesse caso podemos utilizar uma instncia global da classe TMultiReadExclusiveWriteSynchronizer. A classe TMultiReadExclusiveWriteSynchronizer tem os mtodos BeginRead e EndRead para proteger um bloco que pode ser acessado por vrias threads desde que nenhuma outra thread esteja dentro de uma seo BeginWrite EndWrite. Os mtodos BeginWrite e EndWrite protegem uma parte do programa que acessa e modifica a memria. Vrias threads podem entrar na seo BeginRead-EndRead ao mesmo tempo desde que nenhuma outra thread esteja dentro de uma seo BeginWrite-EndWrite. UNIVERSIDADE DO ESTADO DA BAHIA UNEB Laboratrio de Orientao a Objetos OOLAB http://www.uneb.net/oolab - 9 - Se uma thread A tentar executar BeginWrite e a thread B estiver dentro de uma seo BeginRead-EndRead, a thread A vai dormir, at que a thread B execute EndRead e s ento a thread A prosseguir. Se a thread B executar BeginRead e a thread A estiver dentro de uma seo BeginWrite-EndWrite, a thread B vai dormir at que a thread A execute EndWrite. Veja abaixo. UNIVERSIDADE DO ESTADO DA BAHIA UNEB Laboratrio de Orientao a Objetos OOLAB http://www.uneb.net/oolab - 10 - Concluses Desenvolver uma aplicao multi-thread no Delphi/Kylix relativamente fcil, mas o difcil mesmo garantir a consistncia do programa, trabalhar com threads requer por parte do desenvolvedor muito mais ateno, para se ter uma idia, em alguns casos atualizar um formulrio pode se tornar mais difcil do que criar e manter uma lista generalizada, principalmente se o programador no for experiente. Em muitas aplicaes o uso de threads se faz necessrio, para garantir a performance e muitas vezes at o prprio funcionamento da aplicao. Existem aplicaes que s so concebeis atravs do uso de multi-thread. UNIVERSIDADE DO ESTADO DA BAHIA UNEB Laboratrio de Orientao a Objetos OOLAB http://www.uneb.net/oolab - 11 - Bibliografia Sistemas Operacionais Modernos, Andrew S. Tanenbaum1999. O Help do Delphi. O Help do Kylix. UNIVERSIDADE DO ESTADO DA BAHIA UNEB Laboratrio de Orientao a Objetos OOLAB http://www.uneb.net/oolab - 12 - Autor Edmilson dos Santos de Jesus Edsjbr@yahoo.com.br Estudante do curso de Bacharelado em Anlise de Sistemas 8 Sem. UNEB-BA http://www.uneb.br Integrante do OOLAB-UNEB (Laboratrio de Orientao a Objetos da UNEB) http://www.uneb.net/oolab Analista de Sistemas da Actha Multiformtica http://www.actha.com.br