Docsity
Docsity

Prepare-se para as provas
Prepare-se para as provas

Estude fácil! Tem muito documento disponível na Docsity


Ganhe pontos para baixar
Ganhe pontos para baixar

Ganhe pontos ajudando outros esrudantes ou compre um plano Premium


Guias e Dicas
Guias e Dicas


Elementos de Programação MuiltiThreading em Dephi, Notas de estudo de Cultura

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

Antes de 2010

Compartilhado em 22/08/2009

marco-antonio-cunha-da-silva-5
marco-antonio-cunha-da-silva-5 🇧🇷

1 documento

1 / 88

Toggle sidebar

Esta página não é visível na pré-visualização

Não perca as partes importantes!

bg1
Autor: Constantino Seixas Filho - UFMG
Elementos de
Programação
Multithreading
em Delphi
Sequential Programming Gary Larson
Capítulo
8
pf3
pf4
pf5
pf8
pf9
pfa
pfd
pfe
pff
pf12
pf13
pf14
pf15
pf16
pf17
pf18
pf19
pf1a
pf1b
pf1c
pf1d
pf1e
pf1f
pf20
pf21
pf22
pf23
pf24
pf25
pf26
pf27
pf28
pf29
pf2a
pf2b
pf2c
pf2d
pf2e
pf2f
pf30
pf31
pf32
pf33
pf34
pf35
pf36
pf37
pf38
pf39
pf3a
pf3b
pf3c
pf3d
pf3e
pf3f
pf40
pf41
pf42
pf43
pf44
pf45
pf46
pf47
pf48
pf49
pf4a
pf4b
pf4c
pf4d
pf4e
pf4f
pf50
pf51
pf52
pf53
pf54
pf55
pf56
pf57
pf58

Pré-visualização parcial do texto

Baixe Elementos de Programação MuiltiThreading em Dephi e outras Notas de estudo em PDF para Cultura, somente na Docsity!

Autor: Constantino Seixas Filho - UFMG

Elementos de

Programação

Multithreading

em Delphi

Sequential Programming – Gary Larson

Capítulo

Elementos de Programação Multithreading em Delphi 1

Introdução

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.

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:

  • Escolha File / New /Other/Thread Object para criar uma nova Unit que contem um objeto derivado da classe TThread.
  • Defina o método Execute do objeto thread inserindo o código que deve ser executado quando a thread for executada.

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

A solução da Exclusão Mútua no WNT

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.

Criação de threads no velho estilo C like.

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.

Sincronização entre threads

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]);