Pour calculer une factorielle sur un ou plusieurs coeurs de calcul.
Ce module utilise un mutex pour synchroniser les différentes tache.
Affiche le temps d'execution et une boucle de temporisation permet de ralentir un peut le calcul.
Utilisa un thread qui attend que les N threads déclarés soient terminés.
N correspond au nombre de coeur de calcul présent sur le µ-microprocesseur.
Permet ainsi d'optimiser avec un traitement paralléle toutes les boucles demandant une forte charge de calcul.
Source / Exemple :
unit factorielle;
//Ecrit par denis bertin stéphane le 25 juillet 2013.
//Pour calculer une factorielle sur un ou plusieurs coeurs de calcul.
//Ce module utilise un mutex pour synchroniser les différentes tache.
//Affiche le temps d'execution et une boucle de temporisation permet de ralentir un peut le calcul.
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TAffichage_factorielle = class(TForm)
Label1: TLabel;
Edit_nombre: TEdit;
Label2: TLabel;
Edit_resultat: TEdit;
Button1: TButton;
Label3: TLabel;
Edit_mono: TEdit;
Edit_multi: TEdit;
Label4: TLabel;
result_multi_coeur: TLabel;
Edit_result_multi_coeur: TEdit;
Label_sur_x_coeur: TLabel;
procedure Button1Click(Sender: TObject);
private
{ Déclarations privées }
public
{ Déclarations publiques }
end;
var
Affichage_factorielle: TAffichage_factorielle;
implementation
{$R *.dfm}
uses SyncObjs;
const Number_of_process_unit = 31;
var ThreadsRunning:integer;
var Lock:SyncObjs.TCriticalSection;
var Table_thread : array[0..Number_of_process_unit] of extended;
type
// Objet de gestion des affinités processeur.
TCPU = Class
Protected
FCPUMask : Array[0..Number_of_process_unit] Of Boolean ; // Mapping physique des processeurs autorisés pour le processus courant.
FCPUMap : Array[0..Number_of_process_unit] Of Cardinal ; // Mapping logique des processeurs, contient un masque d'affinité.
FCPUCount : Cardinal ; // Nombre de processeurs utilisables, conditionne la limite supérieure de CPUMap.
// Accesseur "Count".
Function GetCPUCount : Cardinal ;
Public
// Constructeur
Constructor Create ;
// Récupération du nombre de CPU / coeurs du système.
// Les processeurs sont ensuite numérotés de 0 à (Count-1).
Property Count : Cardinal Read GetCPUCount ;
// Force le thread courant à basculer sur le processeur passé en paramètre.
// Lève une exception en cas d'erreur.
// Ne lève PAS d'erreur (mais ne fait rien non plus) en cas de numéro de CPU invalide.
Procedure SwitchTo ( Const CPUIndex : Cardinal ) ;
End Platform ;
type
TSeulement_Wait = class(TThread)
Constructor Create;
protected procedure Execute; override;
end;
type
Thread_Factorielle = class(TThread)
Constructor Create(un_index,a_int_begin,a_int_ending:integer);
Procedure ThreadDone(Sender: TObject);
protected procedure Execute; override; {Méthode recouverte en français}
Public
index,commencement,finissement:integer; {Denis B le 20.7.2013}
end;
{ Cette classe TCPU importé depuis internet le saviez-vous ?}
constructor TCPU.Create;
begin
// Initialisation des structures d'affinité processeur.
FCPUCount:=0;
FillChar(FCPUMask,SizeOf(FCPUMask),0);
FillChar(FCPUMap,SizeOf(FCPUMap),0);
// Calcul direct du nombre de CPU.
GetCPUCount;
end;
Function TCPU.GetCPUCount : Cardinal ;
Var I, ProcessMask, SystemMask : Cardinal ;
Begin
// Inutile de tout déclencher si on a déjà le nombre de CPU...
If (FCPUCount=0) Then
Begin
// On va récupérer le nombre de CPU.
FCPUCount:=0 ;
// On compte les bits d'affinité.
Win32Check(GetProcessAffinityMask(GetCurrentProcess,ProcessMask,SystemMask));
// Bon, on a le masque : on va calculer sa taille.
For I:=0 To pred(Number_of_process_unit) Do
Begin
// Explosage du masque binaire vers un tableau de booléens.
FCPUMask[I]:=(ProcessMask And (1 Shl I))<>0 ;
// On compte les CPU utilisables, et on crée la map d'assignation.
// Le contenu de CPUMap, à l'indice donné, est donc le masque d'affinité à utiliser.
If FCPUMask[I] Then
Begin
FCPUMap[FCPUCount]:=(1 Shl I) ;
Inc(FCPUCount);
End;
End;
End;
// Le nombre de CPU est correct quel que soit le cas, on renvoie donc le résultat.
Result:=FCPUCount ;
End;
Procedure TCPU.SwitchTo ( Const CPUIndex : Cardinal ) ;
Begin
If (CPUIndex<FCPUCount) Then
If (SetThreadAffinityMask(GetCurrentThread,FCPUMap[CPUIndex])=0) Then
RaiseLastOSError ;
End;
Constructor TSeulement_Wait.Create;
begin
inherited Create(False);
self.Priority:=tpLowest;
end; {TSeulement_Wait.Create}
//Utilisation d'un Mutex pour ne pas décrémenter le compteur deux fois en même temps.
Procedure TSeulement_Wait.Execute;
var encore:boolean;
begin
encore:=True;
while encore do
begin
Lock.Enter;
encore:=ThreadsRunning<>0;
Lock.Leave;
end; {While encore}
end; {TSeulement_Wait.Execute}
Constructor Thread_Factorielle.Create(un_index,a_int_begin,a_int_ending:integer);
begin
inherited Create(False);
self.FreeOnTerminate:=True;
self.index:=un_index;
self.commencement:=a_int_begin;
self.finissement:=a_int_ending;
end;
procedure Thread_Factorielle.Execute;
var i,j:integer;
s:extended;
begin
For i:=self.commencement to self.finissement do
begin
Table_thread[self.index]:=Table_thread[self.index]*i;
//Boucle de temporisation
for j:=1 to 20000 do s:=sin(j);
end;
end;
Procedure Thread_Factorielle.ThreadDone(Sender: TObject);
begin
Lock.Enter;
Dec(ThreadsRunning); //Pour que la fin du wait attend que ThreadsRunning=0!
Lock.Leave;
end;
function Convertir_ce_numerique_en_string_separer_par_des_point(a_value:integer):string;
var i,j:integer;
s,ss:string;
begin
ss:='';
s:=inttostr(a_value);
j:=length(s);
for i:=1 to length(s) do
begin
ss:=ss+char(s[i]);
dec(j);
if (j mod 3=0) and (j<>0) then
ss:=ss+'.';
end;
Convertir_ce_numerique_en_string_separer_par_des_point:=ss;
end;
procedure TAffichage_factorielle.Button1Click(Sender: TObject);
var i,j,k,jusqua,ithread:integer;
n,s:Extended;
time_begin:integer;
time_fining:integer;
uncpu:TCPU;
nombre_de_coeur:integer;
un_thread_wait:TSeulement_Wait;
modulo,posit_one,posit_two:integer;
begin
jusqua:=strtoint(Edit_nombre.text);
time_begin:=gettickcount;
n:=1;
for i:=1 to jusqua do
begin
n:=n*i;
//Boucle de temporisation
for j:=1 to 20000 do s:=sin(j);
end;
Edit_resultat.Text:=floattostr(n);
time_fining:=gettickcount;
Edit_mono.Text:=Convertir_ce_numerique_en_string_separer_par_des_point(time_fining-time_begin)+' Millisecondes';
uncpu:=TCPU.Create;
nombre_de_coeur:=uncpu.Count;
uncpu.Free;
Label_sur_x_coeur.Caption:='sur '+inttostr(nombre_de_coeur)+ ' coeur(s)';
if nombre_de_coeur>1 then
begin
time_begin:=gettickcount;
for i:=1 to nombre_de_coeur do
Table_thread[i]:=1;
Lock:=TCriticalSection.Create;
ThreadsRunning:=nombre_de_coeur;
un_thread_wait:=TSeulement_Wait.Create;
for ithread:=1 to nombre_de_coeur do
begin
modulo:=jusqua div nombre_de_coeur;
if ithread=1 then
posit_one:=1
else
posit_one:=modulo*pred(ithread);
if ithread=nombre_de_coeur then
posit_two:=jusqua
else
posit_two:=pred(modulo*ithread);
with Thread_Factorielle.create(
ithread,posit_one,posit_two) do
OnTerminate := ThreadDone;
end;
un_thread_wait.waitfor;
Lock.Free;
n:=1;
for i:=1 to nombre_de_coeur do
n:=n*Table_thread[i];
time_fining:=gettickcount;
Edit_result_multi_coeur.text:=floattostr(n);
Edit_multi.Text:=Convertir_ce_numerique_en_string_separer_par_des_point(time_fining-time_begin)+' Millisecondes';
end
else
Edit_multi.Text:='Monocoeur';
end; {TAffichage_factorielle.Button1Click}
end.
Conclusion :
Utilise un mutex pour synchroniser n tache selon le nombre de coeur.
Vous n'êtes pas encore membre ?
inscrivez-vous, c'est gratuit et ça prend moins d'une minute !
Les membres obtiennent plus de réponses que les utilisateurs anonymes.
Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.
Le fait d'être membre vous permet d'avoir des options supplémentaires.