Sign in Join
Wiki copytemporary

Example of multi-threaded application: array of threads/es: what changed

Revision 0 to 1. Removed lines have a minus sign; added lines have a plus sign.

Title: Example of multi-threaded application: array of threads/es

OldNewLine
1+Aquí se muestra un ejemplo de cómo crear un montón de hilos y esperar a que terminen su trabajo (no se necesita ninguna sincronización). Estoy escribiendo esta tutoría, ya que no era evidente escribir este programa después de leer [[Multithreaded Application Tutorial/es|Tutoría de Aplicaciones Multihilo]]. La aplicación está escrita para Linux x86_64.
2+
3+   Supongamos que tenemos el siguiente bucle:
4+
5+``` pascal
6+ var resultados: integer;
7+ Archivo: text;
8+ begin
9+ ...
10+ for i:=1 to n do begin
11+ MiProcedimiento(resultado);
12+ Writeln(Archivo,resultado);
13+ end;
14+ ...
15+```
16+
17+   Este bucle se ejecuta u procedimiento que "calcula" algún "resultado". Después de esto, escribe esta matriz a un archivo de texto... Ahora queremos dividir este trabajo a muchos hilos en paralelo.
18+
19+   Para hacer esto, necesitamos llevar a cabo los siguientes pasos:
20+
21+## 1. Gestión de memoria
22+
23+   Tus hilos pueden leer las variables siempre que se necesite, pero no debería escribirse ningún dato en las estas variables (global), al mismo tiempo. Así que los hilos no pueden escribir nada en una variable como "resultado". Y no será capaz de escribir en Archivo. Por otra parte, estaba interesado en escribir los resultados en un archivo en orden (de 1 a n), y los hilos no lo harán. Así que el primer paso es crear la matriz global de los resultados (una celda por hilo). Si el procedimiento debe escribir algo a varias variables, se deben crear varias matrices o una matriz de registros.
24+
25+   Usamos una unidad independiente para las variables globales:
26+
27+``` pascal
28+ unit Global;
29+ {$mode objfpc}{$H+}
30+ interface
31+ uses Classes, SysUtils;
32+
33+ var resultados: array [1..100] of threads; //No vamos a crear más de 100 hilos.
34+
35+ implementation
36+
37+ end.
38+```
39+
40+## 2. Añadimos la clase de los hilos
41+
42+   También usamos una unidad separada para ella. Así hay que describir la propiedad *Terminated*, como pública (para utilzarla desde el programa principal).
43+
44+``` pascal
45+ unit MisHilos;
46+
47+ {$mode objfpc}{$H+}
48+
49+ interface
50+
51+ uses
52+ Classes, SysUtils;
53+
54+ Type
55+ TMiHilo = class(TThread)
56+ private
57+ protected
58+ procedure Ejecutar; override;
59+ public
60+ inicio,fin: integer; //Se inician estos campos antes de ejecutar el hilo. Por lo que cada hilo recibirá una parte de la tarea.
61+ property Terminado;
62+ Constructor Create(CrearSuspendido : boolean);
63+ end;
64+
65+ implementation
66+
67+ constructor TMiHilo.Create(CrearSuspendido : boolean);
68+ begin
69+ LibeararAlTerminar := True;
70+ inherited Create(CrearSuspendido);
71+ end;
72+
73+ procedure TMiHilo.Ejecutar;
74+ var
75+ i: integer;
76+ begin
77+ i:=inicio;
78+ while (not Terminado) and (i<=fin) do
79+ begin
80+ MiProcedimiento(resultados[i]);
81+ inc(i);
82+ if i=fin+1 then Terminar;
83+ end;
84+ end;
85+ end.
86+```
87+
88+## 3. Reescribir el programa principal
89+
90+   Es necesario añadir "cthreads" a la unidad principal, ¡no a la unidad con los hilos!
91+
92+   Consejos: mi IDE de Lazarus no fue capaz de depurar aplicaciones *multihilo*, si no se usa "pthreads". He leído que si utiliza "cmem ', el programa funciona más rápido, pero recomiendo que para comprobar cada caso particular (mi programa se cuelga cuando uso" cmem).
93+
94+``` pascal
95+ uses cthreads,
96+ // cmem,
97+ // pthreads,
98+ Classes, SysUtils, CustApp, MyThreads, Global
99+
100+ var
101+ MatrizHilos: array [1..100] of TMiHilo; //No vamos a crear más de 100 hilos.
102+ i, numero_de_hilos: integer;
103+ begin
104+
105+ numero_de_hilos := 100;
106+
107+ while n div numero_de_hilos <1 do dec(numero_de_hilos); //Si n < 100 entonces no tenemos suficientes tareas para 100 hilos.
108+
109+ for i:=1 to numero_de_hilos do begin
110+ MatrizHilos[i]:= TMiHilo.Crear(True);
111+ MatrizHilos[i].inicio:=(i-1)*(n div numero_de_hilos)+1;;
112+ MatrizHilos[i].fin:=i*(n div numero_de_hilos);
113+ MatrizHilos[i].Resumir;
114+ end;
115+
116+ for i:=1 to 10 do if not MatrizHilos[i].Terminado then Sleep(10); //Esperando a que los hilos terminen su trabajo.
117+
118+ for i:=1 to numero_de_hilos * (n div numero_de_hilos) do Writeln(Archivo,resultados[i]); //Escribir los resultados en orden.
119+ //O Se puede calcular una suma aquí y escribirlo.
120+ //Ahora debemos terminar parte de la tarea que no puede ser dividido en 100 hilos.
121+ //Por ejemplo, si n=10050 entonces 10000 se dividirá en 100 hilos.
122+ //Y los últimos 50 (< 100) que debe terminar en el modo no paralelo.
123+ //Así lo hago.
124+ //En su lugar, se puede escribir algo como: "si i = numero_de_hilos entonces MatrizHilos[i].fin: = n;. 'En el ciclo anterior.
125+ //En este casoel último hilo debe terminar el trabajo.
126+
127+ if n numero_de_hilos <> 0 then
128+ for i:=(n div numero_de_hilos) + 1 to n do begin
129+ MiProcedimiento(resultado);
130+ Writeln(Archivo,resultado);
131+ end;
132+
133+ Terminar;
134+ end;
135+```
136+
137+---
138+*From the Free Pascal wiki, page "Example of multi-threaded application: array of threads/es", as it stood on 2020-02-14 after a change by Trev, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*

Back to history