Camaradas,
O CreateThread é uma função disponibilizada pela plataforma Windows ( API ) cedida pela Kernel32, ela é responsável pela criação de um objeto Thread no windows que efetua operações no processador sendo gerenciado pelo windows na parte da fila de processamento e outros eventos.
| Delphi | | copy code | | ? |
| 1 | function CreateThread(lpThreadAttributes: Pointer; |
| 2 | dwStackSize: DWORD; lpStartAddress: TFNThreadStartRoutine; |
| 3 | lpParameter: Pointer; dwCreationFlags: DWORD; var lpThreadId: DWORD): THandle; stdcall; |
| 4 | {$EXTERNALSYM CreateThread} |
| Delphi | | copy code | | ? |
| 1 | type |
| 2 | TThreadStartProc = function (Parameter: Pointer): Integer; stdcall; |
O retorno da API CreateThread é o Handle da Thread, como sabemos Handles são números que identificam objetos Windows e através de APIs podemos controla-los com muita especialidade.
Agora, se você chegou até aqui, é porque realmente está interessado em aprender a utilizar as tão famosas thread, e a primeira coisa que lhe digo:
Lembre-se Processamentos Específicos, se você quiser uma interação com algum componente na interface gráfica você precisa de criar uma sincronia com a VCL.
Então agora sem o susto, podemos iniciar a utilização:
Primeiramente baixe o código-fonte abaixo, abra o delphi e compile. Execute o aplicativo, clique em Run e veja que alguns processos são disparados, mais especificamente 100 processos paralelos.
Nesse teste eu criei um pequeno controle de sincronia boolean feita através da variável SimpleLock, perceba que ao iniciar o processo de adicionar linha no TMemo mmoLog eu coloco o valor dela em True, indicando que estou processando algo, e logo no final ao terminar o processo eu coloco o SimpleLock como false, indicando que já terminei o processo. Assim antes de iniciar o processo eu verifico se o SimpleLock está em True, e se estiver eu espero até que ele esteja em False para iniciar um novo processamento.
Agora partindo para o entendimento direto do código
Escrevi um record, que servira de parametro para a minha função da Thread, como preciso de passar o parametro como ponteiro ( Pointer ) escrevi o tipo PMyParallelParams que nada mais é que uma indicação que o podemos guardar um ponteiro do objeto TMyParallelParams.
| Delphi | | copy code | | ? |
| 01 | |
| 02 | type |
| 03 | PMyParallelParams = ^TMyParallelParams; |
| 04 | TMyParallelParams = record |
| 05 | A, B: integer; |
| 06 | ThreadName: string; |
| 07 | Handle: THandle; |
| 08 | Callback: procedure(AParam: PMyParallelParams) of object; |
| 09 | end; |
| 10 |
A variável A é responsável por guardar o tamanho do passo ( Step Size ) que deve ser feito para se atingir o valor da variável B.
ThreadName o próprio nome já diz tudo, é aonde guardamos o nome que idenfica a thread das demais.
Handle é o Handle do Objeto Thread para manipulação da própria Thread durante o processamento.
Callback é o procedimento que a Thread deve chamar no final do seu processamento.
Perceba que todos esses valores foram criados por mim, e não fazem parte de um Thread nativa, ou seja, o código foi estruturado para funcionar com essa estrutura e nenhum processo é automático, todas as variáveis tem sua razão de existir, coisa que você podera escrever também para seus processamento próprios sendo específico para cada tipo de finalidade desejada.
A declaração da SimpleLock para sincronia e do procedimento de Callback que informaremos para a nossa Thread.
| Delphi | | copy code | | ? |
| 1 | |
| 2 | ... |
| 3 | private |
| 4 | { Private declarations } |
| 5 | public |
| 6 | SimpleLock: boolean; |
| 7 | procedure ReceiveThreadEnd(AParam: PMyParallelParams); |
| 8 | end; |
| 9 |
Como podemos notar a criação de uma Thread para uma finalidade específica que não dependa de outros processos se torna quase completamente paralela, então no meu caso, coloquei um nome na função bem em conchavo com a especialidade da mesma.
| Delphi | | copy code | | ? |
| 01 | function MyParallelProc(AParam: PMyParallelParams): Integer; stdcall; |
| 02 | var |
| 03 | i: integer; |
| 04 | begin |
| 05 | i := 0; |
| 06 | while i < AParam^.B do |
| 07 | begin |
| 08 | i := i + AParam^.A; |
| 09 | Sleep(100); |
| 10 | end; |
| 11 | AParam^.Callback(AParam); |
| 12 | Dispose(AParam); |
| 13 | EndThread(0); |
| 14 | CloseHandle(AParam^.Handle); |
| 15 | Result := 0; |
| 16 | end; |
O código é bem simples, algumas notações da parte final devem ser feitas:
| Delphi | | copy code | | ? |
| 01 | var |
| 02 | i: integer; |
| 03 | dwNull: DWORD; |
| 04 | Params: PMyParallelParams; |
| 05 | begin |
| 06 | SimpleLock := false; |
| 07 | lblStillRunning.Caption := '100'; |
| 08 | for i := 1 to 100 do |
| 09 | begin |
| 10 | New(Params); |
| 11 | Randomize; |
| 12 | Params^.A := Random(10) + 1; |
| 13 | Params^.B := Random(100); |
| 14 | Params^.ThreadName := 'Thread' + IntToStr(i); |
| 15 | Params^.Callback := ReceiveThreadEnd; |
| 16 | Params^.Handle := CreateThread(nil, 0, @MyParallelProc, Params, |
| 17 | 0, dwNull); |
| 18 | end; |
Esse é o código de quando clicamos no TButton btnRun. Este código é o coração de todo nosso processo de entendimento de como iniciar um processo paralelo com o CreateThread, então atenção as explicações (Em tópicos para facilitar).
-
nil para definir que não teremos configuração de segurança nem tampouco de compartilhamento.
0 para indicar que o StackSize vai ser o padrão, 1Mb.
@MyParallelProc para indicar aonde está a function MyParallelProc que será o inicío da Thread.
Params para indicar que o parametro a ser passado é o ponteiro do nosso record. Lembre-se que pra cada passo no Loop criamos um novo Params, no uso do New(), então até que nenhuma Thread chegue ao seu términio teremos 100 objetos TMyParallelParams na memória.
0 para indicar que a Thread deve ser iniciada imediatamente após retornar o Handle da mesma.
dwNull como não utilizaremos o ThreadID em nada, não precisamos guardar este valor.
A estrutura básica então é essa, não vou comentar muito sobre a parte da sincronia com a VCL pois isso será assunto para um outro artigo.
Qualquer dúvida, sugestão, crítica ou agradecimentos, fique avontade.
Lembrando mais uma vez, se você possuí material interessante sobre Delphi e outros,
você pode postar o site na CommunityLinks
Abraço a todos
