Soyez le premier à donner votre avis sur cette source.
Snippet vu 5 789 fois - Téléchargée 22 fois
//////////////////////////////////////////////////////////////////////////////// // Nom du fichier : DLLThreadSynchronize.pas // // Auteur : S.Mazuir // // Date : 10/03/2010 // // Révision : 1 // // Version : Delphi6 // // Plateformes : Win32 // // // // Notes : // // Unité permettant de gérér sans modification du code la synchronisation // // des évènements générés par des threads créés dans une ou plusieurs DLL. // // // // Utilisation : Ajouter cette unité au projet de l'application et de // // chaque DLL dans laquelle sont créés des threads. Aucune modification de // // code nécessaire. // // // // Principe de fonctionnement : Utilisation d'un FileMapping pour partager // // les pointeurs d'objets necessaires entre l'application et les DLL // // chargeant cette unité. Un objet est créé pour chaque DLL, et surcharge // // la variable globale de procedure WakeMainThread. Lorsqu'une // // synchronisation d'évènement est demandée dans une DLL, cet objet ajoute // // son pointeur dans une liste globale (protégée par une section critique), // // et active le thread de surveillance du module pricipal de l'application, // // qui synchronise un évènement dans lequel il propage la synchronisation // // a toutes les DLL qui l'ont demandé a travers les objets placés dans la // // liste globale. // // // // Change log : // // 10/03/2010 - SMA : Création // // // //////////////////////////////////////////////////////////////////////////////// unit DllThreadsSynchronize; interface implementation uses Forms, Classes, Windows, SyncObjs, SysUtils; Type TCheckSynchronizeFunc = function: Boolean; // Objet créé dans chaque DLL permettant de surcharger la variable de procedure globale // WakeMainThread et de redispatcher la méthode CheckSynchronize (Classes.pas) TSyncObj = Class private FLocalCheckSynchronize : TCheckSynchronizeFunc; public Procedure DLLWakeMainThread(Sender : TObject); Procedure DLLCheckSynchronize; Property LocalCheckSynchronize : TCheckSynchronizeFunc read FLocalCheckSynchronize write FLocalCheckSynchronize; end; // Thread de surveillance éxecuté dans le module principal (exe) // C'est lui qui redistribue la synchronisation depuis le thread // principal de l'application vers chaque DLL qui l'a demandé // via un synchronize() TSyncThread = Class(TThread) private Procedure DLLSynchronize; public procedure Execute; override; end; // Structure partagée entre tous les modules de l'application qui utilisent cette unité // via un FileMapping. Cette structure partage les pointeurs des objets communs // entre tous les modules. TSharedStruct = Packed record SyncList : TList; // Liste globale des TSyncObj necessitant une synchronisation DllSyncThread : TSyncThread; // Pointeur vers le thread de controle CriticalSection : TCriticalSection; // Pointeur vers la section critique protégeant la SyncList Signal : THandle; // Handle du signal (event) permettant de controler le thread de controle end; PSharedStruct = ^TSharedStruct; var DllThreadSyncObj : TSyncObj; DllSyncThread : TSyncThread; FSyncList : TList; FCriticalSection : TCriticalSection; FSignal : THandle; MappingHandle : THandle; SharedStruct : PSharedStruct; OldDllProc : TDLLProc; //****************************************************************************// { TSyncObj } // Objet créé dans chaque DLL permettant de surcharger la variable de procedure globale // WakeMainThread et de redispatcher la méthode CheckSynchronize (Classes.pas) procedure TSyncObj.DLLCheckSynchronize; begin // On appelle le CheckSynchronize de la DLL dans laquelle a été créé l'objet FLocalCheckSynchronize; end; procedure TSyncObj.DLLWakeMainThread(Sender : TObject); begin FCriticalSection.Enter; // Protection de la liste globale try try FSyncList.Add(Self); // Ajout de l'objet dans la liste globale : la DLL necessite une synchronisation finally SetEvent(FSignal); // Activation du thread de controle end; finally FCriticalSection.Leave; end; end; //****************************************************************************// { TSyncThread } // Thread de surveillance éxecuté dans le module principal (exe) // C'est lui qui redistribue la synchronisation depuis le thread // principal de l'application vers chaque DLL qui l'a demandé // via un synchronize() // Méthode synchronisée par le thread de controle procedure TSyncThread.DLLSynchronize; var FLocalSyncList : TList; begin // On utilise une liste locale pour pouvoir traiter // tranquillement les objets a traiter en dehors de la section // critique de protection de la liste globale, // car cette section critique peut provoquer des interbloquages // avec le ThreadLock de l'unité Classes.pas, qui est vérouillé pendant // le CheckSynchronize. Ainsi, le CheckSynchronize de chaque DLL est appelé // en dehors de notre section critique. FLocalSyncList := TList.Create; try FCriticalSection.Enter; // Protection de la liste globale try if FSyncList <> nil then begin // Transfert des éléments de la liste globale vers la liste locale while FSyncList.Count > 0 do begin FLocalSyncList.Add(FSyncList[0]); FSyncList.Delete(0); end; end; finally FCriticalSection.Leave; end; // Synchronisation des DLL en dehors de notre section critique : // pas de risques d'interblocages while FLocalSyncList.Count > 0 do begin TSyncObj(FLocalSyncList[0]).DLLCheckSynchronize; // Appel du CheckSynchronize de la DLL dans laquelle a été créé l'objet FLocalSyncList.Delete(0); end; finally FLocalSyncList.Free; end; end; // Boucle principale du thread de controle procedure TSyncThread.Execute; begin while not Terminated do begin WaitForSingleObject(FSignal, INFINITE); // Attente du signal demandant la synchronisation d'une DLL ResetEvent(FSignal); if Terminated then Exit; // Synchronisation d'une méthode locale dans laquelle la synchronisation // sera propagée aux DLL qui l'ont demandé Synchronize(DLLSynchronize); end; end; // Initialisation du module principal (exe) Procedure InitMainModule; var MappingName : String; begin MappingName := ExtractFileName(Application.Title) + '::' + IntToStr(GetCurrentProcessId); // Création d'un zone mémoire partagée pour l'échange des pointeurs d'objets communs avec les DLL MappingHandle := CreateFileMapping($FFFFFFFF, nil, PAGE_READWRITE, 0, SizeOf(TSharedStruct), PChar(MappingName)); if MappingHandle <> 0 then begin // Initialisation du pointeur de la structure partagée SharedStruct := MapViewOfFile(MappingHandle, FILE_MAP_ALL_ACCESS, 0, 0, SizeOf(TSharedStruct)); // Création des objets partagés FSyncList := TList.Create; SharedStruct^.SyncList := FSyncList; DllSyncThread := TSyncThread.Create(True); SharedStruct^.DllSyncThread := DllSyncThread; FCriticalSection := TCriticalSection.Create; SharedStruct^.CriticalSection := FCriticalSection; FSignal := CreateEvent(nil, True, False, ''); SharedStruct^.Signal := FSignal; // Initialisation du thread de controle ResetEvent(FSignal); DllSyncThread.Resume; end; end; // Initialisation d'une DLL Procedure InitLib; var MappingName : String; begin MappingName := ExtractFileName(Application.Title) + '::' + IntToStr(GetCurrentProcessId); // Ouverture d'un handle vers la zone de mémoire partagée (préalablement créée par le module principal) MappingHandle := CreateFileMapping($FFFFFFFF, nil, PAGE_READWRITE, 0, SizeOf(TSharedStruct), PChar(MappingName)); if MappingHandle <> 0 then begin // Initialisation du pointeur de la structure partagée SharedStruct := MapViewOfFile(MappingHandle, FILE_MAP_ALL_ACCESS, 0, 0, SizeOf(TSharedStruct)); // Récupération des pointeurs d'objets partagés FSyncList := SharedStruct^.SyncList; DllSyncThread := SharedStruct^.DllSyncThread; FCriticalSection := SharedStruct^.CriticalSection; FSignal := SharedStruct^.Signal; // Création de l'objet de gestion de la synchronisation pour la DLL DllThreadSyncObj := TSyncObj.Create; WakeMainThread := DllThreadSyncObj.DLLWakeMainThread; // Surcharge de la variable globale de procédure WakeMainThread de la DLL DllThreadSyncObj.LocalCheckSynchronize := CheckSynchronize; // Mémorisation du pointeur de procedure CheckSynchronize de la DLL end; end; // Finalisation du module principal Procedure FinalizeMainModule; begin // Arret et libération du thread de controle SharedStruct^.DllSyncThread.FreeOnTerminate := True; SharedStruct^.DllSyncThread.Terminate; SetEvent(SharedStruct^.Signal); // Libération des objets partagés et fermeture des handles du signal et du FileMapping SharedStruct^.SyncList.Free; SharedStruct^.CriticalSection.Free; CloseHandle(SharedStruct^.Signal); UnmapViewOfFile(SharedStruct); CloseHandle(MappingHandle); end; // Finalisation d'une DLL Procedure FinalizeLib; begin // fermeture du partage du FileMapping UnmapViewOfFile(SharedStruct); // Libération de l'objet de synchronization de la DLL DllThreadSyncObj.Free; end; // Chargement de la DLL Procedure DLLEntryPoint(Reason: Integer); begin InitLib; // On effectue notre initialisation DllProc := OldDllProc; // puis on réaffecte la procédure de point d'entrée d'origine end; // Initialisation de l'unité initialization begin if IsLibrary then // Si c'est une DLL begin OldDllProc := DllProc; // On mémorise le point d'entrée de la DLL DllProc := @DLLEntryPoint; // puis on le remplace par notre propre point d'entrée end else InitMainModule; // Ce n'est pas une DLL, initialisation du module principal (exe) end; // Finalisation de l'unité finalization begin if IsLibrary then // Si c'est une DLL FinalizeLib // Finalisation de la DLL else FinalizeMainModule; // Sinon finalisation du module principal end; end.
8 nov. 2011 à 13:54
Il faudrait mettre à jour les types de procédures utilisés dans ce code pour les rendre compatible en leur ajoutant les même arguments, et en appelant la méthode CheckSynchronize avec les arguments attendus.
3 nov. 2011 à 18:29
Quelqu'un peut m'aider?
13 mars 2010 à 21:38
A mettre absolument dans sa trousse à outils.
Un grand Bravo.
10 mars 2010 à 14:36
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.