Ir para o conteúdo

Simular multithreading

Implementação em Pascal

Hoje proponho a simulação de multithreading em Pascal. É certo que o resultado é algo rudimentar, mas torna-se imensamente útil em pequenos pormenores, por exemplo, estar um processo a decorrer enquanto se espera uma tecla premida por parte do utilizador.

Esta torna-se, então, uma daquelas situações em que o módulo (ou unit) CRT encaixa perfeitamente numa programação de boas práticas e não em embelezamento exagerado e com um toque de non-sense.

O princípio é este: enquanto uma tecla não for premida, realizar um conjunto de acções.

Em "pascalês":

repeat
      while not KeyPressed do begin
            // Acções a realizar
            delay(10);
      end;
until (ReadKey = #13);

Note-se que as acções a realizar não devem demorar séculos a decorrer, se não o utilizador prime a tecla e tem de esperar uma eternidade para que seja assumida.

O delay de 10 milissegundos evita que o ciclo esteja sempre em execução, o que consome recursos, em especial do processador - em média, sem o delay, a CPU tem uma utilização entre 20 a 40% - não é agradável ouvir a ventoinha que nem um avião, certo? :-D

Neste caso, a tecla que se espera é a #13, ou seja, o Enter.

Se a acção a realizar é praticamemente instantânea, então o delay pode ser de 50 milissegundos. Porquê? O ser humano tem uma visão com uma frequência de 20fps, ou seja, os olhos captam 20 imagens por segundo. Sendo um segundo 1000 milissegundos, 1000ms / 20fps = 50ms. Assim, o utilizador prime a tecla e, apesar dos 50ms de delay, vai-lhe dar a sensação de que foi instantâneo.

E voilá, um multi-threading rudimentar, que poupa recursos ao computador, e parece instantâneo ao utilizador final.

Implementação em Delphi

program Project1;

{$APPTYPE CONSOLE}

uses
  SysUtils, Classes;


type
    TTeste = class(TThread)
    protected
      procedure Execute; override;
    end;

var
   i:integer;
   Teste:TTeste;

procedure TTeste.Execute;
var
   i:integer;
begin
     NameThreadForDebugging('ThreadTeste');
     for i := 1 to 1000 do
         begin
              writeln('T2: ',i);
              sleep(10);
         end;
end;

begin  // 1ª thread é iniciada, automaticamente com o programa principal
     try
        Teste:=TTeste.Create;  // 2ª Thread é iniciada, o código de TTeste.Execute é executado

        for i := 1 to 1000 do  // Continuação do código da 1ª Thread
            begin
                 writeln('T1: ',i,' = ',chr(i mod 26));
                 sleep(10);
            end;

        Teste.Destroy;  // Libertada a 2ª Thread

     except
        on E: Exception do
           Writeln(E.ClassName, ': ', E.Message);
     end;
     Writeln('Enter para terminar. . .');
     Readln;
end.  // Fim da 1ª Thread, juntamente com o fim do programa