| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240 |
- { $HDR$}
- {**********************************************************************}
- { Unit archived using Team Coherence }
- { Team Coherence is Copyright 2002 by Quality Software Components }
- { }
- { For further information / comments, visit our WEB site at }
- { http://www.TeamCoherence.com }
- {**********************************************************************}
- {}
- { $Log: 10355: IdSync.pas
- {
- { Rev 1.2 3/11/04 12:28:58 AM RLebeau
- { Improper cast fixed.
- }
- {
- { Rev 1.1 05.6.2003 ã. 11:25:36 DBondzhev
- { Fix for Memleak when notification object is about to be executed in main
- { thread.
- { Also WaitFor to wait for notification to be executed.
- }
- {
- { Rev 1.0 2002.11.12 10:54:24 PM czhower
- }
- unit IdSync;
- interface
- // Author: Chad Z. Hower - a.k.a. Kudzu
- uses
- Classes,
- IdGlobal, IdThread;
- type
- TIdSync = class(TObject)
- protected
- FThread: TIdBaseThread;
- public
- constructor Create; overload; virtual;
- constructor Create(AThread: TIdBaseThread); overload; virtual;
- procedure DoSynchronize; virtual; abstract;
- procedure Synchronize;
- //
- property Thread: TIdBaseThread read FThread;
- end;
- TIdNotify = class(TObject)
- protected
- FMainThreadUsesNotify: Boolean;
- public
- constructor Create; virtual; // here to make virtual
- procedure DoNotify; virtual; abstract;
- procedure Notify;
- procedure WaitFor;
- class procedure NotifyMethod(AMethod: TThreadMethod);
- //
- property MainThreadUsesNotify: Boolean read FMainThreadUsesNotify write FMainThreadUsesNotify;
- end;
- TIdNotifyMethod = class(TIdNotify)
- protected
- FMethod: TThreadMethod;
- public
- constructor Create(AMethod: TThreadMethod); reintroduce;
- procedure DoNotify; override;
- end;
- implementation
- uses
- SysUtils;
- type
- // This is done with a NotifyThread instead of PostMessage because starting with D6/Kylix Borland
- // radically modified the mecanisms for .Synchronize. This is a bit more code in the end, but
- // its source compatible and does not rely on Indy directly accessing any OS APIs and performance
- // is still more than acceptable, especially considering Notifications are low priority.
- TIdNotifyThread = class(TIdBaseThread)
- protected
- FEvent: TIdLocalEvent;
- FNotifications: TThreadList;
- public
- procedure AddNotification(ASync: TIdNotify);
- constructor Create(ASuspended: Boolean);
- destructor Destroy; override;
- procedure Execute; override;
- end;
- var
- GNotifyThread: TIdNotifyThread = nil;
- procedure CreateNotifyThread;
- begin
- if GNotifyThread = nil then begin
- GNotifyThread := TIdNotifyThread.Create(False);
- end;
- end;
- { TIdSync }
- constructor TIdSync.Create(AThread: TIdBaseThread);
- begin
- inherited Create;
- FThread := AThread;
- end;
- constructor TIdNotify.Create;
- begin
- inherited Create;
- end;
- procedure TIdNotify.Notify;
- begin
- if InMainThread and (MainThreadUsesNotify = False) then begin
- DoNotify;
- Free;
- end else begin
- CreateNotifyThread;
- GNotifyThread.AddNotification(Self);
- end;
- end;
- class procedure TIdNotify.NotifyMethod(AMethod: TThreadMethod);
- begin
- TIdNotifyMethod.Create(AMethod).Notify;
- end;
- constructor TIdSync.Create;
- begin
- CreateNotifyThread;
- FThread := GNotifyThread;
- end;
- procedure TIdSync.Synchronize;
- begin
- FThread.Synchronize(DoSynchronize);
- end;
- { TIdNotifyThread }
- procedure TIdNotifyThread.AddNotification(ASync: TIdNotify);
- begin
- FNotifications.Add(ASync);
- FEvent.SetEvent;
- end;
- constructor TIdNotifyThread.Create(ASuspended: Boolean);
- begin
- FEvent := TIdLocalEvent.Create;
- FNotifications := TThreadList.Create;
- // Must be before - Thread starts running when we call inherited
- inherited Create(ASuspended);
- end;
- destructor TIdNotifyThread.Destroy;
- begin
- // Free remaining Notifications if thre is somthing that is still in
- // the queue after thread was terminated
- with FNotifications.LockList do try
- while Count > 0 do begin
- TIdNotify(Items[0]).Free;
- Delete(0);
- end;
- finally FNotifications.UnlockList; end;
- FreeAndNil(FNotifications);
- FreeAndNil(FEvent);
- inherited Destroy;
- end;
- procedure TIdNotifyThread.Execute;
- // NOTE: Be VERY careful with making changes to this proc. It is VERY delicate and the order
- // of execution is very important. Small changes can have drastic effects
- var
- LNotifications: TList;
- LNotify: TIdNotify;
- begin
- repeat
- FEvent.WaitFor;
- // If terminated while waiting on the event or during the loop
- while not Terminated do begin
- try
- LNotifications := FNotifications.LockList;
- try
- if LNotifications.Count = 0 then begin
- Break;
- end;
- LNotify := TIdNotify(LNotifications.Items[0]);
- LNotifications.Delete(0);
- finally
- FNotifications.UnlockList;
- end;
- try
- Synchronize(LNotify.DoNotify);
- finally
- FreeAndNil(LNotify);
- end;
- except // Catch all exceptions especially these which are raised during the application close
- end;
- end;
- until Terminated;
- end;
- { TIdNotifyMethod }
- constructor TIdNotifyMethod.Create(AMethod: TThreadMethod);
- begin
- FMethod := AMethod;
- end;
- procedure TIdNotifyMethod.DoNotify;
- begin
- FMethod;
- end;
- procedure TIdNotify.WaitFor;
- Var
- LNotifyIndex: Integer;
- begin
- LNotifyIndex := 0;
- while LNotifyIndex <> -1 do begin
- with GNotifyThread.FNotifications.LockList do try
- LNotifyIndex := IndexOf(Self);
- finally
- GNotifyThread.FNotifications.UnlockList;
- end;
- Sleep(10);
- end;
- end;
- initialization
- finalization
- // Will free itself using FreeOnTerminate
- if GNotifyThread <> nil then begin
- GNotifyThread.Terminate;
- GNotifyThread.FEvent.SetEvent;
- GNotifyThread.WaitFor;
- FreeAndNil(GNotifyThread);
- end;
- end.
|