
















































































Estude fácil! Tem muito documento disponível na Docsity
Ganhe pontos ajudando outros esrudantes ou compre um plano Premium
Prepare-se para as provas
Estude fácil! Tem muito documento disponível na Docsity
Prepare-se para as provas com trabalhos de outros alunos como você, aqui na Docsity
Encontra documentos específicos para os exames da tua universidade
Prepare-se com as videoaulas e exercícios resolvidos criados a partir da grade da sua Universidade
Responda perguntas de provas passadas e avalie sua preparação.
Ganhe pontos para baixar
Ganhe pontos ajudando outros esrudantes ou compre um plano Premium
Em Delphi existem classes pré definidas que facilitam a criação dos objetos básicos que usaremos neste texto: Threads, Eventos, CriticalSections, etc. Para todos os demais elementos é possível definir componentes que encapsulem um conjunto de entidades básicas e proporcionem as funcionalidades desejadas
Tipologia: Notas de estudo
1 / 88
Esta página não é visível na pré-visualização
Não perca as partes importantes!

















































































Autor: Constantino Seixas Filho - UFMG
Sequential Programming – Gary Larson
Elementos de Programação Multithreading em Delphi 1
Criação de threads: classe TThread
Para criar uma thread, devemos criar uma classe derivada (descendente) da classe base: TThread. Cada instância desta nova classe será uma thread de execução. Como já foi estudado, as threads compartilham o mesmo espaço de memória do processo que as criou.
Para criar e usar um novo objeto do tipo thread:
A maior parte dos métodos que acessam um objeto CLX ( Component Libray for cross platform ) e atualizam um formulário, devem ser chamados a partir da thread principal ou usar um objeto de sincronização como será estudado.
E x e m p l o 1 : C r i a n d o T h r e a d s
O trecho de programa abaixo cria a classe TprintThread como derivada da classe TThread. A função virtual Execute é então substituída por um código próprio.
U n i t E 2 1 C r e a t e T h r e a d s M a i n
unit E21CreateThreadsMain;
interface
uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, Printth;
type TForm1 = class (TForm) btnThread1: TButton; btnThread2: TButton;
Elementos de Programação Multithreading em Delphi 3
type TprintThread = class (TThread) private Index: Integer; protected procedure Execute; override ; procedure Print; public constructor Create (Value: Integer); // Novo construtor: passa parâmetro na criação end ;
implementation
uses E21CreateThreadsMain, Graphics;
// Imprementa passagem de parâmetro para inicializar a thread
constructor TPrintThread.Create(Value: Integer); begin Index := Value; inherited Create(False); end ;
Procedure TPrintThread.Print; var strIndex: string; begin strIndex := IntToStr(Index); Form1.lstListBox1.Items.Add(strIndex); end ;
Procedure TPrintThread.Execute; var i: Integer; begin for i:=1 to 6 do Synchronize(Print); end ;
end.
Elementos de Programação Multithreading em Delphi 4
Figura 1 - Tela do exemplo 1
O método Create da classe TThread é utilizado para criar uma thread.
T T h r e a d. C r e a t e
constructor Create(
CreateSuspended: Boolean // True: a thread é criada no estado suspenso
T T h r e a d. E x e c u t e
Suspende a thread temporariamente até que seja emitido um Resume.
Procedure Execute; virtual; abstract;
Fornece um método abstrato que contém o código que é executado quando a thread é executada. Esta função se sobrepões à função virtual e fornece o código da thread a ser executada. Esta função é responsável por verificar o valor da propriedade Terminated para determinar quando a thread deve terminar.
Não se deve usar as propriedades e métodos de outros objetos diretamente no corpo do método Execute. O uso destes objetos deve ser separado em outro procedimento que deve ser chamado como parâmetro do método Synchronize (veja exemplo 1).
Elementos de Programação Multithreading em Delphi 6
property ThreadID: THandle;
Terminated Indica que o término da thread foi pedido.
O método terminate ativa o flag Terminated.
Suspended Solicita suspensão da thread.
Priority Prioridade da thread
property Priority: Integer;
type TThreadPriority = (tpIdle, tpLowest, tpLower, tpNormal, tpHigher, tpHighest, tpTimeCritical);
property Priority: TThreadPriority;
ReturnValue Valor retornado pela thread
property ReturnValue: Integer
FreeOnTerminate Deve ser definido como TRUE para liberar a thread quando terminar. Se for FALSE, a aplicação deve terminar a thread explicitamente.
OnTerminate Ocorre após o método Execute da thread ter retornado e antes da thread ser destruída.
property OnTerminate: TNotifyEvent;
O programador deve escrever um handler para o evento OnTerminate após o término da execução da thread. O handler será chamado no contexto da thread principal, o que significa que os métodos e propriedades CLX podem ser chamados livremente.
Alterando a prioridade das threads
Para alterar a prioridade de uma thread ela deve ser criada no estado suspenso, a propriedade prioridade deve ser alterada e a thread deve ser liberada:
E x e m p l o : MyThread := TMyThread.Create(True); // Cria a thread em estado suspenso MyThread.Priority := tpLower; //Muda prioridade para nível abaixo de normal MyThread.Resume; // Executa a thread
Elementos de Programação Multithreading em Delphi 7
Lock/Unlock (Classe TCanvas)
Pode-se prevenir que duas ou mais threads utilizem o mesmo objeto VCL ( Visual Component Library ), simultaneamente, bloqueando o seu acesso através do método Lock da classe TCanvas e descendentes. O acesso é liberado através do método Unlock.
Outra alternativa é o uso do método synchronize da classe TThread.
E x e m p l o 2 - I n s t r u ç ã o L o c k d a c l a s s e C a n v a s
E 2 1 C r e a t e T h r e a d s M a i n v 4. p a s
unit E21CreateThreadsMainv4;
interface
uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, Printthv4;
type TForm1 = class (TForm) btnThread1: TButton; btnThread2: TButton; btnThread3: TButton; lstListBox1: TListBox; procedure btnThread1Click(Sender: TObject);
private { Private declarations } PT: array [1..3] of TPrintThread; // Cria três threads public { Public declarations } end ;
var Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.btnThread1Click(Sender: TObject); var Index: Integer; begin
Elementos de Programação Multithreading em Delphi 9
Canvas.Unlock; end ; Sleep(10); end // for end ;
end.
Figura 2 - Criação de threads e uso da instrução Lock
Ao rodar o programa, acione as três teclas para iniciar as três threads. Na ListBox você verá a saída das threads sendo impressas entremeadamente.
No Delphi é possível criar threads no velho estilo do C/C++. Para isto basta utilizar a diretiva BeginThread e passar os parâmetros compatíveis com a versão C++ da função:
function BeginThread(
Attribute: PthreadAttr, // Atributos da thread ThreadFunc: TthreadFunc, // Função que representa a thread Parameter: Pointer, // Apontador para parâmetro a ser passado para a thread Var ThreadId: Cardinal // Variável passada por referência para receber o ThreadId. ): Integer;
Elementos de Programação Multithreading em Delphi 10
O protótipo da função é como se segue:
Function(Parameter: Pointer): Integer;
Este exemplo serve apenas para ilustrar esta possibilidade que só deve ser utilizada em casos extremos. Deve-se sempre preferir a criação de threads utilizando a classe TThread.
E x e m p l o 3 : C i a ç ã o d e t h r e a d s u t i l i z a n d o a d i r e t i v a B e g i n T h r e a d
// Demonstração do uso de criação de threads em Delphi // // Versão 2: Uso da diretiva BeginThread // // Autor: Constantino Seixas Filho Data: 03/06/ // // Comentários: Uma maneira primitiva de criar threads em Delphi é através // da diretiva BeginThread. Neste caso o corpo da thread é definido na // mesma Unit do programa principal.
unit E21BeginThread;
interface
uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls;
type //Record para manter a informação de uma thread TThreadInfo = record Active : Boolean; ThreadHandle : integer; ThreadId : Cardinal; end ;
TForm1 = class (TForm) btnThread1: TButton; btnThread2: TButton; btnThread3: TButton; lstListBox1: TListBox; procedure btnThread1Click(Sender: TObject); procedure OnClose(Sender: TObject; var Action: TCloseAction); private Index: Integer; public ThreadInfo: array [0..2] of TThreadInfo; // Mantém informações da thread public
Elementos de Programação Multithreading em Delphi 12
ExitCode: DWORD; begin for Index:=0 to 2 do begin if ThreadInfo[Index].ThreadHandle <> 0 then begin WaitForSingleObject(ThreadInfo[Index].ThreadHandle, INFINITE); // Espera morte das threads GetExitCodeThread(ThreadInfo[Index].ThreadHandle, ExitCode); CloseHandle(ThreadInfo[Index].ThreadHandle); end end end ; end.
M u t e x
Para usar Mutex em Delphi use o código nativo da API:
// Ao criar o formulário: hMutex := CreateMutex(nil, false, nil);
// Para entrar na seção crítica: WaitForSingleObject(hMutex, INFINITE);
...... // Saindo da seção crítica: ReleaseMutex(hMutex);
// Ao destruir o formulário: CloseHandle(hMutex);
A instrução WaitForSingleObject é semelhante à função correspondente da API Win32, apenas o seu uso em Pascal é que tem sintaxe ligeiramente diferente: mas possui um retorno diferente:
if WaitForSingleObject(hMutex, 0) <> wait_TimeOut then ***
W a i t F o r S i n g l e O b j e c t
DWORD WaitForSingleObject(
HANDLE hHandle, // handle para um objeto do kernel DWORD dwMilliseconds // tempo máximo que desejamos esperar );
Elementos de Programação Multithreading em Delphi 13
Comentários sobre os parâmetros:
hHandle Handle para objeto do kernel que será sinalizado. dwMilliseconds Tempo de timeout. Após este tempo as função retornará independente da sinalização ter ocorrido. INFINITE – Não desejamos timeout 0 – Testa se foi sinalizado e retorna
Retorno da função:
Status Interpretação WAIT_OBJECT_0 Objeto foi sinalizado WAIT_TIMEOUT Ocorreu timeout WAIT_ABANDONED Uma thread proprietária de um Mutex terminou (realizou ExitThread) sem liberá-lo. O objeto Mutex será estudado ainda neste capítulo. WAIT_FAILED A função falhou
E x e m p l o 4 : U s o d e M u t e x
E 3 1 M u t e x. p a s
Este problema foi apresentado no capítulo 3. Uma variável global, representada por um array de inteiros é acessada por múltiplas threads, as quais a preenchem com valores diferentes. Cada vez que o botão Exibir Dados é clicado, os valores correntes dos membros da variável global são exibidos.
unit E31Mutex;
interface
uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, MyThread;
type TForm1 = class (TForm) Button1: TButton; Button2: TButton; Edit1: TEdit; Edit2: TEdit; Edit3: TEdit; Edit4: TEdit; Edit5: TEdit; Edit6: TEdit; Edit7: TEdit;
Elementos de Programação Multithreading em Delphi 15
procedure TForm1.FormDestroy(Sender: TObject); begin CloseHandle (hMutex); // Fecha Handle para Mutex end ;
procedure TForm1.Button2Click(Sender: TObject); begin // Coloque a primeira e última instruções em comentário e veja o resultado WaitForSingleObject(hMutex, INFINITE); Edit1.Text := IntToStr(Registro[1]); Edit2.Text := IntToStr(Registro[2]); Edit3.Text := IntToStr(Registro[3]); Edit4.Text := IntToStr(Registro[4]); Edit5.Text := IntToStr(Registro[5]); Edit6.Text := IntToStr(Registro[6]); Edit7.Text := IntToStr(Registro[7]); Edit8.Text := IntToStr(Registro[8]); Edit9.Text := IntToStr(Registro[9]); Edit10.Text := IntToStr(Registro[10]); ReleaseMutex(hMutex); end ;
end.
M y T h r e a d. p a s
unit MyThread;
interface
uses Windows, Classes, SysUtils;
type TMyThread = class (TThread) private Index: Integer; protected procedure Execute; override ; public constructor Create (Value: Integer); end ;
var Registro: array [1..10] of Integer; hMutex: THandle;
implementation
Elementos de Programação Multithreading em Delphi 16
uses Graphics;
// Implementa passagem de parâmetro para inicializar a thread constructor TMyThread.Create(Value: Integer); begin Index := Value; inherited Create(False); end ;
Procedure TMyThread.Execute; var i: Integer; begin Randomize(); while (TRUE) do begin WaitForSingleObject(hMutex, INFINITE); for i:=1 to 4 do Registro[i]:= Index; Sleep(Random(100)); for i:=5 to 7 do Registro[i]:= Index; Sleep(Random(100)); for i:=8 to 10 do Registro[i]:= Index; ReleaseMutex(hMutex); end end ;
end.
Figura 3 - Demonstrativo: E31MutexDemo
Elementos de Programação Multithreading em Delphi 18
finally LockX.Release; end ;
E x e m p l o 5 : U s o d e T c r i t i c a l S e c t i o n
O programa que se segue é um trecho da solução para o problema anterior empregando a classe TcriticalSection. A solução completa se encontra no CD.
E 3 1 C r i t i c a l S e c t i o n. p a s
unit E31CriticalSection;
interface
uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, SyncObjs , E31CSMyThread;
type TForm1 = class (TForm) Button1: TButton; Button2: TButton; Edit1: TEdit; Edit2: TEdit; Edit3: TEdit; Edit4: TEdit; Edit5: TEdit; Edit6: TEdit; Edit7: TEdit; Edit8: TEdit; Edit9: TEdit; Edit10: TEdit; Label1: TLabel; Label2: TLabel; Label3: TLabel; Label4: TLabel; Label5: TLabel; Label6: TLabel; Label7: TLabel; Label8: TLabel; Label9: TLabel; Label10: TLabel; procedure Button1Click(Sender: TObject); procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure Button2Click(Sender: TObject);
private
Elementos de Programação Multithreading em Delphi 19
{ Private declarations } PT: array [1..5] of TMyThread; // Threads associadas public { Public declarations } end ; var Form1: TForm1; Index: Integer = 0;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject); begin if Index < 5 then // Cria até 5 threads begin Inc(Index); // Index: 1.. PT[Index] := TMyThread.Create(Index); // cria thread end else Button1.Enabled := False; // Desabilita botão de criação end ;
procedure TForm1.FormCreate(Sender: TObject); var i:Integer; begin for i:=1 to 10 do Registro[i]:= 0; MyCS := TCriticalSection.Create; end ;
procedure TForm1.FormDestroy(Sender: TObject); begin MyCS.Free; // Fecha Handle para Mutex end ;
procedure TForm1.Button2Click(Sender: TObject); begin // Coloque a primeira e última instruções em comentário e veja o resultado MyCS.Enter; Edit1.Text := IntToStr(Registro[1]); Edit2.Text := IntToStr(Registro[2]); Edit3.Text := IntToStr(Registro[3]); Edit4.Text := IntToStr(Registro[4]); Edit5.Text := IntToStr(Registro[5]); Edit6.Text := IntToStr(Registro[6]); Edit7.Text := IntToStr(Registro[7]); Edit8.Text := IntToStr(Registro[8]); Edit9.Text := IntToStr(Registro[9]); Edit10.Text := IntToStr(Registro[10]);