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?
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.
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