Introducció

La programació multifil i paral·lela permet que una aplicació executi múltiples tasques simultàniament, aprofitant millor els recursos del sistema i millorant el rendiment. En Delphi, això es pot aconseguir utilitzant fils (threads) i altres tècniques de programació paral·lela.

Conceptes Clau

Fils (Threads)

  • Fil (Thread): Un fil és la unitat bàsica d'execució dins d'un procés. Cada fil té el seu propi conjunt de registres, pila i estat, però comparteix la memòria del procés amb altres fils.
  • Procés: Un procés és un programa en execució que pot contenir múltiples fils.

Programació Paral·lela

  • Paral·lelisme: Execució simultània de múltiples tasques per aprofitar els processadors múltiples.
  • Concurrent: Execució de múltiples tasques de manera que es superposen en el temps, però no necessàriament simultàniament.

Creació de Fils en Delphi

Exemple Bàsic de Creació de Fils

uses
  System.Classes, System.SysUtils;

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

procedure TMyThread.Execute;
begin
  // Codi que s'executarà en el fil
  while not Terminated do
  begin
    // Realitzar tasques
    Sleep(1000); // Simular treball
  end;
end;

procedure StartThread;
var
  MyThread: TMyThread;
begin
  MyThread := TMyThread.Create(True); // Crear el fil suspès
  MyThread.FreeOnTerminate := True;   // Alliberar memòria automàticament
  MyThread.Start;                     // Iniciar el fil
end;

Explicació del Codi

  • TMyThread: Definim una classe que hereta de TThread i sobreescrivim el mètode Execute per definir el codi que s'executarà en el fil.
  • Execute: Aquest mètode conté el codi que s'executarà en el fil. En aquest exemple, es realitzen tasques en un bucle fins que el fil es terminin.
  • StartThread: Aquesta funció crea una instància de TMyThread, la configura per alliberar memòria automàticament quan es terminin i inicia el fil.

Sincronització de Fils

Problema de Condicions de Carrera

Quan múltiples fils accedeixen i modifiquen dades compartides simultàniament, poden sorgir condicions de carrera, que poden causar comportaments inesperats.

Utilització de Seccions Crítiques

var
  CriticalSection: TRTLCriticalSection;

procedure TMyThread.Execute;
begin
  while not Terminated do
  begin
    EnterCriticalSection(CriticalSection);
    try
      // Accés a dades compartides
    finally
      LeaveCriticalSection(CriticalSection);
    end;
    Sleep(1000);
  end;
end;

initialization
  InitializeCriticalSection(CriticalSection);

finalization
  DeleteCriticalSection(CriticalSection);

Explicació del Codi

  • TRTLCriticalSection: Utilitzem una secció crítica per protegir l'accés a dades compartides.
  • EnterCriticalSection i LeaveCriticalSection: Aquests mètodes garanteixen que només un fil pugui accedir a les dades compartides al mateix temps.

Programació Paral·lela amb TTask

Exemple d'Ús de TTask

uses
  System.Threading, System.SysUtils;

procedure ParallelTask;
begin
  TTask.Run(
    procedure
    begin
      // Codi que s'executarà en paral·lel
      Sleep(1000); // Simular treball
    end
  );
end;

Explicació del Codi

  • TTask.Run: Crea i executa una tasca en paral·lel. El codi dins del bloc procedure s'executarà en un fil separat.

Exercicis Pràctics

Exercici 1: Crear un Fil que Compti Fins a 10

Descripció: Crea un fil que compti fins a 10, mostrant cada número en la consola amb un retard d'un segon entre cada número.

Solució:

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

procedure TCountingThread.Execute;
var
  i: Integer;
begin
  for i := 1 to 10 do
  begin
    Writeln(i);
    Sleep(1000);
  end;
end;

procedure StartCountingThread;
var
  CountingThread: TCountingThread;
begin
  CountingThread := TCountingThread.Create(True);
  CountingThread.FreeOnTerminate := True;
  CountingThread.Start;
end;

Exercici 2: Sincronitzar l'Accés a una Variable Compartida

Descripció: Crea dos fils que incrementin una variable compartida 100 vegades cadascun. Utilitza una secció crítica per evitar condicions de carrera.

Solució:

var
  SharedCounter: Integer;
  CriticalSection: TRTLCriticalSection;

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

procedure TIncrementingThread.Execute;
var
  i: Integer;
begin
  for i := 1 to 100 do
  begin
    EnterCriticalSection(CriticalSection);
    try
      Inc(SharedCounter);
    finally
      LeaveCriticalSection(CriticalSection);
    end;
    Sleep(10);
  end;
end;

procedure StartIncrementingThreads;
var
  Thread1, Thread2: TIncrementingThread;
begin
  InitializeCriticalSection(CriticalSection);
  try
    SharedCounter := 0;
    Thread1 := TIncrementingThread.Create(True);
    Thread2 := TIncrementingThread.Create(True);
    Thread1.FreeOnTerminate := True;
    Thread2.FreeOnTerminate := True;
    Thread1.Start;
    Thread2.Start;
    Thread1.WaitFor;
    Thread2.WaitFor;
    Writeln('Final Counter Value: ', SharedCounter);
  finally
    DeleteCriticalSection(CriticalSection);
  end;
end;

Conclusió

En aquesta secció, hem après els conceptes bàsics de la programació multifil i paral·lela en Delphi, incloent la creació de fils, la sincronització de dades compartides i l'ús de TTask per a la programació paral·lela. Aquests coneixements són fonamentals per desenvolupar aplicacions eficients i responsives. En el següent mòdul, explorarem el desenvolupament basat en components, una altra característica poderosa de Delphi.

Curs de Programació Delphi/Object Pascal

Mòdul 1: Introducció a Delphi/Object Pascal

Mòdul 2: Estructures de Control i Procediments

Mòdul 3: Treballant amb Dades

Mòdul 4: Programació Orientada a Objectes

Mòdul 5: Funcions Avançades de Delphi

Mòdul 6: Desenvolupament d'Interfícies Gràfiques amb VCL i FMX

Mòdul 7: Desenvolupament Web i Mòbil

Mòdul 8: Millors Pràctiques i Patrons de Disseny

Mòdul 9: Projecte Final

© Copyright 2024. Tots els drets reservats