home *** CD-ROM | disk | FTP | other *** search
/ Delphi Magazine Collection 2001 / Delphi Magazine Collection 20001 (2001).iso / DISKS / Issue40 / Threads / HVMultiThreadMain.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1998-11-03  |  5.1 KB  |  171 lines

  1. unit HVMultiThreadMain;
  2. //
  3. // Written by Hallvard Vassbotn, hallvard@falcon.no
  4. //
  5. // Based on source code Copyright (c) 1998 by Reuters Group PLC
  6. // Reproduction and/or distribution of source code or DCUs strictly prohibited.
  7. //
  8. // For publication in The Delphi Magazine only
  9. //
  10. interface
  11.  
  12. uses
  13.   Windows,
  14.   Classes,
  15.   Forms,
  16.   ExtCtrls,
  17.   HVSyncObjs,
  18.   HVSignalList
  19.   ;
  20.  
  21. type
  22.   TMultiThreadedMainLoop = class(TObject)
  23.   private
  24.     FHasBeenIdle : boolean;
  25.     FIdleTimer   : TTimer;
  26.     FOldAppIdle  : TIdleEvent;
  27.     FSignalList: TSignalList;
  28.     procedure SetIdleTimerInterval(Value: integer);
  29.     function GetIdleTimerInterval: integer;
  30.   protected
  31.     procedure OnIdleTimer(Sender: TObject);
  32.     procedure AppIdle(Sender: TObject; var Done: boolean);
  33.   public
  34.     constructor Create;
  35.     destructor Destroy; override;
  36.  
  37.     procedure TriggerOnHandle(aHandle: THandle; anOnTrigger: TNotifyEvent);
  38.     procedure TriggerOnObject(aHandleObject: THandleObject; anOnTrigger: TNotifyEvent);
  39.     procedure TriggerOnThread(aThread: TThread; anOnTrigger: TNotifyEvent);
  40.  
  41.     property SignalList: TSignalList read FSignalList;
  42.     property IdleTimerInterval: integer read GetIdleTimerInterval write SetIdleTimerInterval;
  43.   end;
  44.  
  45. function MultiThreadedMainLoop: TMultiThreadedMainLoop;
  46.  
  47. implementation
  48.  
  49. uses
  50.   HVUtils
  51.   ;
  52.  
  53. { TMultiThreadedMainLoop }
  54.  
  55. constructor TMultiThreadedMainLoop.Create;
  56. begin
  57.   inherited Create;
  58.   // Create the list used for the thread signals
  59.   FSignalList := TSignalList.Create;
  60.  
  61.   // Save and setup OnIdle handler, lets hope newcomers do the same...
  62.   FOldAppIdle := Application.OnIdle;
  63.   Application.OnIdle := AppIdle;
  64.  
  65.   FIdleTimer := TTimer.Create(nil);
  66.   FIdleTimer.Interval := 100;  // every 100 ms, about 10 times pr second
  67.   FIdleTimer.OnTimer := OnIdleTimer;
  68.   FIdleTimer.Enabled := true;
  69. end;
  70.  
  71. destructor TMultiThreadedMainLoop.Destroy;
  72. begin
  73.   // Stop being nagged by the timer
  74.   FreeObject(FIdleTimer);
  75.   // Restore the old OnIdle handler
  76.   Application.OnIdle := FOldAppIdle;
  77. //  FreeObject(FIdleHookList);
  78.   FreeObject(FSignalList);
  79.   inherited Destroy;
  80. end;
  81.  
  82. function TMultiThreadedMainLoop.GetIdleTimerInterval: integer;
  83. begin
  84.   Result := FIdleTimer.Interval;
  85. end;
  86.  
  87. procedure TMultiThreadedMainLoop.SetIdleTimerInterval(Value: integer);
  88. begin
  89.   FIdleTimer.Interval := Value;
  90. end;
  91.  
  92. procedure TMultiThreadedMainLoop.TriggerOnHandle(aHandle: THandle; anOnTrigger: TNotifyEvent);
  93. begin
  94.   FSignalList.AddSignal(THandleSignal.Create(aHandle, anOnTrigger));
  95. end;
  96.  
  97. procedure TMultiThreadedMainLoop.TriggerOnObject(aHandleObject: THandleObject; anOnTrigger: TNotifyEvent);
  98. begin
  99.   FSignalList.AddSignal(TObjectSignal.Create(aHandleObject, anOnTrigger));
  100. end;
  101.  
  102. procedure TMultiThreadedMainLoop.TriggerOnThread(aThread: TThread; anOnTrigger: TNotifyEvent);
  103. begin
  104.   FSignalList.AddSignal(TThreadSignal.Create(aThread, anOnTrigger));
  105. end;
  106.  
  107. procedure TMultiThreadedMainLoop.AppIdle(Sender: TObject; var Done: boolean);
  108. // Whenever the application becomes idle, i.e. there are no messages in the
  109. // message queue, this procedure is entered.
  110. begin
  111.   // The default case for the old idle event
  112.   // handler should be that it is done processing
  113.   Done := true;
  114.  
  115.   // Call any old idle event handler
  116.   // - this could be extended with an idle hook chain
  117.   if Assigned(FOldAppIdle) then
  118.     FOldAppIdle(Sender, Done);
  119.  
  120.   // WaitUntil handles all signaled objects for the main thread
  121.   if Done then
  122.     // If the old idle event handler is done,
  123.     // wait until there is a message for us (blocking)
  124.     FSignalList.WaitUntil(INFINITE, [wrMessage])
  125.   else
  126.     // If the old idle event handler is not done yet,
  127.     // just check for signaled objects or messages (non-blocking)
  128.     FSignalList.WaitUntil(0       , [wrMessage, wrTimeOut]);
  129.  
  130.   // Tell the timer-loop that we have actully been idle
  131.   FHasBeenIdle := true;
  132.  
  133.   // Now return to the message loop in TApplication and
  134.   // let it have a look at the message for us
  135.   // Note that we will normally return with Done = true.
  136.   // This will call WaitMessage in TApplication.Idle, but it will not
  137.   // block because we already know there is a message in the message queue
  138. end;
  139.  
  140. procedure TMultiThreadedMainLoop.OnIdleTimer(Sender: TObject);
  141. // This timer handler is called (roughly) 10 times pr second
  142. // This is to allow signaled objects to be handled even when other
  143. // message loops than TApplication is running (e.g. menu, dialog box etc.)
  144. begin
  145.   // Some time since we were idle?
  146.   if not FHasBeenIdle then
  147.   begin
  148.     // Empty the list of signaled objects
  149.     while (SignalList.WaitOneAndTrigger(0) = wrSignaled) do
  150.       {Loop};
  151.   end;
  152.   // Reset the idle flag
  153.   FHasBeenIdle := false;
  154. end;
  155.  
  156. var
  157.   MultiThreadedMainLoopInstance: TMultiThreadedMainLoop;
  158.  
  159. function MultiThreadedMainLoop: TMultiThreadedMainLoop;
  160. begin
  161.   if not Assigned(MultiThreadedMainLoopInstance) then
  162.     MultiThreadedMainLoopInstance := TMultiThreadedMainLoop.Create;
  163.  Result := MultiThreadedMainLoopInstance;
  164. end;
  165.  
  166. initialization
  167. finalization
  168.   FreeObject(MultiThreadedMainLoopInstance);
  169.  
  170. end.
  171.