zoukankan      html  css  js  c++  java
  • TAxThread

    http://www.cybletter.com/index.php?id=3

    http://www.cybletter.com/index.php?id=30

    Source Code

    http://www.cybletter.com/index.php?s=file_download&id=3

    Full Paper

    www.cybletter.com/index.php?s=file_download&id=4 

    Alexandr Štefek
    Military Academy in Brno
    alexandr@stefek.cz

    Abstract

    This paper present implementation of parallel execution.

    If we use parallel proces in programs we have to solve synchronization.

    We show the effective implementation of parallel execution without using critical sections, semaphores, mutexes or events.

    Thread

    The thread is system object defined on platform Win32.

    SDK defines some method for thread creating and handling.

    In real implementation must be defined the procedure for all parallel procedures.

    If in system Win32 thread create new window handle then all messages are handled by this thread.

    For this fact commes the idea of problem solution.

    We can simply create window handle on executing thread.

    When this thread executes loop for message handling it is possible to send special message to thread window handle.

    The parameters of message can be method to execute and parameter for this method.

    But method has 8 bytes and the message parameter only 4.

    So we have allocate memory block, copy method to this block and send adress of allocated block.

    Coding the method

    We want to create class that has method for sync parallel and async parallel execution of methods.

    Now we show, how to code the 8 byte method to 4 byte adress of method.

    function TAxThread.NotifyEventToPointer( Proc : TNotifyEvent ) : Longint;
    var
      Method : TMethod absolute Proc;
      PMethod : ^TMethod;
    begin
      New( PMethod );
    PMethod^ :
    = Method; Result := Longint( PMethod ); end; procedure TAxThread.AsyncExecuteParallel( Proc : TNotifyEvent; ParamSender : TObject ); begin InterlockedIncrement( FMethodsToExecute ); PostMessageParallel( CM_EXECPROC_WORK_TRHREAD, NotifyEventToPointer( Proc ), Longint( ParamSender ) ); end; procedure TAxThread.ExecProcedure( var Message : TMessage ); var PMethod : ^TMethod; Method : TMethod; Event : TNotifyEvent absolute Method; begin PMethod := Pointer( message.WParam ); Method := PMethod^;
    Event( TObject(
    message.LParam ) );
    Dispose( PMethod );
    if FThreadID = GetCurrentThreadId then InterlockedDecrement( FMethodsToExecute ); end;

    NotifyEventToPointer is method for copying method to memory block.

    Result of this method is adress of memory block.

    Method ExeProcedure takes WParam of message, convert it back to method

    and call decoded method with parametr defined by LParam of message.

    Thread loop

    We have to define thread message loop.

    Delphi define basic thread class TThread.

    This class has virtual method execute.

    Defined class TAxThread is inherited from TThread.

    Method TAxThread.Execute is overrided; 

    procedure TAxThread.Execute;
    var
      Msg : TMsg;
      Done : Boolean;
    begin
      CreateHandleParallel;
      FThreadID := GetCurrentThreadId;
      while not Terminated do
      begin
        if Done then
        begin
          FIdleData := nil;
          WaitMessage;
        end;
        while ProcessMessage( Msg ) do { loop };
        Idle( FIdleData, Done );
      end;
    end;

     At first the class has to create handle (CreateHandleParallel).

    Loop while waits for messages and handles incomming messages (ProcessMessage).

    function TAxThread.ProcessMessage( var Msg : TMsg ) : Boolean;
    begin
      Result := False;
      if PeekMessage( Msg, 0, 0, 0, PM_REMOVE ) thenbegin
        Result := True;
        if Msg.Message <> WM_QUIT then
        begin
          TranslateMessage( Msg );
          DispatchMessage( Msg );
        end
        else
          Terminate;
      end;
    end;

    Calling DispatchMessage dispatch current message to objects for execution.

    If incomming method is CM_EXECUTE (defined in Delphi), then method ExecProcedure is called.

    Sync and async execution

    All parallel processing is sended to execution by message.

    If we use for sending the API function SendMessage then the execution is synchronized

    (actual thread is suspend, the context is switched, message is immediately handled and control is returned to sending thread).

    The API function PostMessage puts the message to message queue and continue in execution.

    When the message is peek from queue, is handled and method is executed.

    // Asynchro execute on parallel thread
    procedure TAxThread.AsyncExecuteParallel( Proc : TNotifyEvent;
      ParamSender : TObject );
    begin
      InterlockedIncrement( FMethodsToExecute );
      PostMessageParallel( CM_EXECPROC, NotifyEventToPointer( Proc ),
        Longint( ParamSender ) );
    end;
    
    // Synchro execute on parallel thread
    procedure TAxThread.SyncExecuteParallel( Proc : TNotifyEvent;
      ParamSender : TObject );
    begin
      InterlockedIncrement( FMethodsToExecute );
      SendMessageParallel( CM_EXECPROC, NotifyEventToPointer( Proc ),
        Longint( ParamSender ) );
    end;

    Introduced method AsyncExecuteParallel is used for async parallel execution

    (execution on selected thread) of method Proc with parameter ParamSender.

    Method SyncExecuteParallel runs method Proc with parameter ParamSender synchronously (waits for execution).

    The thread defines method for execution on main thread (AsyncExecuteMain, SyncExecuteMain).

    Using

    For example of using define class

    type
      TMainForm = class( TForm )
        btnRandomize : TButton;
        imgResult : TImage;
        pbProgress : TProgressBar;
        btnMulti : TButton;
        procedure FormCreate( Sender : TObject );
        procedure FormDestroy( Sender : TObject );
        procedure btnRandomizeClick( Sender : TObject );
        procedure btnMultiClick( Sender : TObject );
      private
        { Private declarations }
        FExecutingThread : TAxThread;
      public
        { Public declarations }
        procedure RandomizeBMP( Data : TObject );
        procedure DoUpdate( Data : TObject );
        procedure Progress( Data : TObject );
      end;

    Private variable FExecutingThread is thread on witch the metods will be executed.

    There are three public method in form of TNotifyEvent (can be executed on selected thread).

    procedure TMainForm.btnRandomizeClick( Sender : TObject );
    var
      PomBMP : TBitmap;
    begin
      if FExecutingThread = nil then
        FExecutingThread := TAxThread.Create;
      PomBMP := TBitmap.Create;
      PomBMP.Width := 200;
      PomBMP.Height := 200;
      PomBMP.PixelFormat := pf24bit;
      FExecutingThread.AsyncExecuteParallel( RandomizeBMP, PomBMP );
    end;

    When user clicked on button then method btnRandomizeClick is called.

    Method calls AsyncExecuteParallel.

    Main thread continue in responsing to user interaction.

    When the thread contrext is switched, FExecutingThread begins execute then method RandomizeBMP.

    procedure TMainForm.RandomizeBMP( Data : TObject );
    var
      CurrentThread : TAxThread;
      PomBMP : TBitmap;
      I : Longint;
      X : Longint;
      Y : Longint;
      Color : Longint;
    begin
      if not( Data is TBitmap ) then
        Exit;
      PomBMP := Data as TBitmap;
      CurrentThread := TAxThread.GetCurrentThread;
      I := 0;
      try
        PomBMP.Canvas.Lock;
        while not CurrentThread.Terminated do
        begin
          Inc( I );
          if I > MaxPoints then
            Break;
          X := Random( 200 );
          Y := Random( 200 );
          Color := Random( 256 ) * 256 * 256 + Random( 256 ) * 256 + Random( 256 );
          if ( I mod ( MaxPoints div 100 ) ) = 0 then
            CurrentThread.SyncExecuteMain( Progress, TObject( I ) );
          // slow for demonstration
          PomBMP.Canvas.Pixels[ X, Y ] := Color;
        end;
      finally
        PomBMP.Canvas.Unlock;
        CurrentThread.AsyncExecuteMain( DoUpdate, PomBMP );
      end;
    end;

    Method RandomizeBMP decode parameter as Bitmap and fills it with some random points.

    When randomize is finished, the thread notify main thread (CurrentThread.AsyncExecuteMain).


    Conclusion


    We present implementation of thread class for async (sync) execution.

    The designed library has very effective method for developing of parallel computing.

      1 unit AxThreads2;
      2 
      3 interface
      4 
      5 uses
      6   Windows, Classes, SysUtils, Controls, Forms, Messages;
      7 
      8 const
      9   CM_EXECPROC = $8FFF;
     10 
     11 type
     12   TIdleEvent = procedure( var Data : TObject; var Done : Boolean ) of object;
     13 
     14   TAxThread = class( TThread )
     15   private
     16     FThreadID : Longint;
     17     FOnIdle : TIdleEvent;
     18     FIdleData : TObject;
     19     FWndHandleParallel : LongWord;
     20     FWndHandleMain : LongWord;
     21 
     22     FMethodsToExecute : Longint;
     23     procedure SetOnIdle( const Value : TIdleEvent );
     24   protected
     25     procedure CreateHandleParallel;
     26     procedure DestroyHandleParallel;
     27     procedure CreateHandleMain;
     28     procedure DestroyHandleMain;
     29 
     30     procedure MessageProcedure( var Message : TMessage ); virtual;
     31 
     32     procedure ExecProcedure( var Message : TMessage ); message CM_EXECPROC;
     33     procedure Execute; override;
     34     procedure Idle( var Data : TObject; var Done : Boolean ); virtual;
     35 
     36     function ProcessMessage( var Msg : TMsg ) : Boolean;
     37 
     38     function NotifyEventToPointer( Proc : TNotifyEvent ) : Longint;
     39   public
     40     constructor Create;
     41     destructor Destroy; override;
     42 
     43     // Posts a null message to parallel thread
     44     procedure WakeUp;
     45 
     46     class function GetCurrentThread : TAxThread;
     47     // sends a message to main thread
     48     function SendMessageMain( Msg, WParam, LParam : LongWord ) : Longint;
     49     // posts a message to main thread
     50     function PostMessageMain( Msg, WParam, LParam : LongWord ) : LongBool;
     51 
     52     // sends a message to parallel thread
     53     function SendMessageParallel( Msg, WParam, LParam : LongWord ) : Longint;
     54     // posts a message to parallel thread
     55     function PostMessageParallel( Msg, WParam, LParam : LongWord ) : LongBool;
     56 
     57     // for compatibility
     58     function SendMessage( Msg, WParam, LParam : LongWord ) : Longint;
     59     function PostMessage( Msg, WParam, LParam : LongWord ) : LongBool;
     60 
     61     // Synchro execute on parallel thread
     62     procedure SyncExecuteParallel( Proc : TNotifyEvent; ParamSender : TObject );
     63     // Asynchro execute on parallel thread
     64     procedure AsyncExecuteParallel( Proc : TNotifyEvent;
     65       ParamSender : TObject );
     66 
     67     // Synchro execute on main thread
     68     procedure SyncExecuteMain( Proc : TNotifyEvent; ParamSender : TObject );
     69     // Asynchro execute on main thread
     70     procedure AsyncExecuteMain( Proc : TNotifyEvent; ParamSender : TObject );
     71 
     72     // for compatibility
     73     procedure SyncExecute( Proc : TNotifyEvent; ParamSender : TObject );
     74     procedure AsyncExecute( Proc : TNotifyEvent; ParamSender : TObject );
     75 
     76     // handle for main thread
     77     property WndHandleMain : LongWord read FWndHandleMain;
     78 
     79     // handle for parallel thread
     80     property WndHandleParallel : LongWord read FWndHandleParallel;
     81 
     82     // idle event for parallel thread
     83     property OnIdle : TIdleEvent read FOnIdle write SetOnIdle;
     84 
     85     property MethodsToExecute : Longint read FMethodsToExecute;
     86 
     87     property Terminated;
     88   end;
     89 
     90 implementation
     91 
     92 { TAxThread }
     93 var
     94   AxThreads : TThreadList;
     95 
     96 procedure TAxThread.CreateHandleParallel;
     97 begin
     98   FWndHandleParallel := AllocateHWnd( MessageProcedure );
     99 end;
    100 
    101 procedure TAxThread.MessageProcedure( var Message : TMessage );
    102 begin
    103   Dispatch( message );
    104 end;
    105 
    106 procedure TAxThread.DestroyHandleParallel;
    107 begin
    108   DeallocateHWnd( FWndHandleParallel );
    109   FWndHandleParallel := 0;
    110 end;
    111 
    112 constructor TAxThread.Create;
    113 begin
    114   // this must by synchonized because of MainThread Context
    115   FMethodsToExecute := 0;
    116 
    117   inherited Create( False );
    118   Synchronize( CreateHandleMain );
    119 
    120   if AxThreads = nil then
    121     AxThreads := TThreadList.Create;
    122 
    123   AxThreads.Add( Self );
    124 end;
    125 
    126 destructor TAxThread.Destroy;
    127 begin
    128   Terminate;
    129   WakeUp;
    130   inherited;
    131   DestroyHandleParallel;
    132   DestroyHandleMain;
    133 
    134   AxThreads.Remove( Self );
    135 end;
    136 
    137 procedure TAxThread.AsyncExecuteParallel( Proc : TNotifyEvent;
    138   ParamSender : TObject );
    139 begin
    140   InterlockedIncrement( FMethodsToExecute );
    141   PostMessageParallel( CM_EXECPROC, NotifyEventToPointer( Proc ),
    142     Longint( ParamSender ) );
    143 end;
    144 
    145 procedure TAxThread.SyncExecuteParallel( Proc : TNotifyEvent;
    146   ParamSender : TObject );
    147 begin
    148   InterlockedIncrement( FMethodsToExecute );
    149   SendMessageParallel( CM_EXECPROC, NotifyEventToPointer( Proc ),
    150     Longint( ParamSender ) );
    151 end;
    152 
    153 procedure TAxThread.ExecProcedure( var Message : TMessage );
    154 var
    155   PMethod : ^TMethod;
    156   Method : TMethod;
    157   Event : TNotifyEvent absolute Method;
    158 begin
    159   PMethod := Pointer( message.WParam );
    160 
    161   Method := PMethod^;
    162   Event( TObject( message.LParam ) );
    163 
    164   Dispose( PMethod );
    165   if FThreadID = GetCurrentThreadId then
    166     InterlockedDecrement( FMethodsToExecute );
    167 end;
    168 
    169 procedure TAxThread.Execute;
    170 var
    171   Msg : TMsg;
    172   Done : Boolean;
    173 begin
    174   CreateHandleParallel;
    175   FThreadID := GetCurrentThreadId;
    176 
    177   while not Terminated do
    178   begin
    179     if Done then
    180     begin
    181       FIdleData := nil;
    182       WaitMessage;
    183     end;
    184     while ProcessMessage( Msg ) do { loop };
    185     Idle( FIdleData, Done );
    186   end;
    187 end;
    188 
    189 procedure TAxThread.CreateHandleMain;
    190 begin
    191   FWndHandleMain := AllocateHWnd( MessageProcedure );
    192 end;
    193 
    194 procedure TAxThread.DestroyHandleMain;
    195 begin
    196   DeallocateHWnd( FWndHandleMain );
    197   FWndHandleMain := 0;
    198 end;
    199 
    200 procedure TAxThread.AsyncExecuteMain( Proc : TNotifyEvent;
    201   ParamSender : TObject );
    202 begin
    203   PostMessageMain( CM_EXECPROC, NotifyEventToPointer( Proc ),
    204     Longint( ParamSender ) );
    205 end;
    206 
    207 procedure TAxThread.SyncExecuteMain( Proc : TNotifyEvent;
    208   ParamSender : TObject );
    209 begin
    210   SendMessageMain( CM_EXECPROC, NotifyEventToPointer( Proc ),
    211     Longint( ParamSender ) );
    212 end;
    213 
    214 function TAxThread.PostMessageMain( Msg, WParam, LParam : LongWord ) : LongBool;
    215 begin
    216   Result := Windows.PostMessage( FWndHandleMain, Msg, WParam, LParam );
    217 end;
    218 
    219 function TAxThread.PostMessageParallel( Msg, WParam, LParam : LongWord )
    220   : LongBool;
    221 begin
    222   while FWndHandleParallel = 0 do
    223     SwitchToThread;
    224 
    225   Result := Windows.PostMessage( FWndHandleParallel, Msg, WParam, LParam );
    226 end;
    227 
    228 function TAxThread.SendMessageMain( Msg, WParam, LParam : LongWord ) : Longint;
    229 begin
    230   Result := Windows.SendMessage( FWndHandleMain, Msg, WParam, LParam );
    231 end;
    232 
    233 function TAxThread.SendMessageParallel( Msg, WParam, LParam : LongWord )
    234   : Longint;
    235 begin
    236   while FWndHandleParallel = 0 do
    237     SwitchToThread;
    238 
    239   Result := Windows.SendMessage( FWndHandleParallel, Msg, WParam, LParam );
    240 end;
    241 
    242 procedure TAxThread.Idle( var Data : TObject; var Done : Boolean );
    243 begin
    244   if Assigned( FOnIdle ) then
    245     FOnIdle( Data, Done )
    246   else
    247     Done := True;
    248 end;
    249 
    250 function TAxThread.ProcessMessage( var Msg : TMsg ) : Boolean;
    251 begin
    252   Result := False;
    253   if PeekMessage( Msg, 0, 0, 0, PM_REMOVE ) then
    254   begin
    255     Result := True;
    256     if Msg.Message <> WM_QUIT then
    257     begin
    258       TranslateMessage( Msg );
    259       DispatchMessage( Msg );
    260     end
    261     else
    262       Terminate;
    263   end;
    264 end;
    265 
    266 procedure TAxThread.SetOnIdle( const Value : TIdleEvent );
    267 begin
    268   FOnIdle := Value;
    269   SendMessageParallel( 0, 0, 0 );
    270 end;
    271 
    272 procedure TAxThread.AsyncExecute( Proc : TNotifyEvent; ParamSender : TObject );
    273 begin
    274   AsyncExecuteParallel( Proc, ParamSender );
    275 end;
    276 
    277 procedure TAxThread.SyncExecute( Proc : TNotifyEvent; ParamSender : TObject );
    278 begin
    279   SyncExecuteParallel( Proc, ParamSender );
    280 end;
    281 
    282 function TAxThread.PostMessage( Msg, WParam, LParam : LongWord ) : LongBool;
    283 begin
    284   Result := PostMessageParallel( Msg, WParam, LParam );
    285 end;
    286 
    287 function TAxThread.SendMessage( Msg, WParam, LParam : LongWord ) : Longint;
    288 begin
    289   Result := SendMessageParallel( Msg, WParam, LParam );
    290 end;
    291 
    292 function TAxThread.NotifyEventToPointer( Proc : TNotifyEvent ) : Longint;
    293 var
    294   Method : TMethod absolute Proc;
    295   PMethod : ^TMethod;
    296 begin
    297   New( PMethod );
    298   PMethod^ := Method;
    299   Result := Longint( PMethod );
    300 end;
    301 
    302 procedure TAxThread.WakeUp;
    303 begin
    304   PostMessageParallel( 0, 0, 0 );
    305 end;
    306 
    307 class function TAxThread.GetCurrentThread : TAxThread;
    308 var
    309   PomList : TList;
    310   PomIndex : Longint;
    311   ThreadID : Longint;
    312 begin
    313   Result := nil;
    314   if AxThreads = nil then
    315     Exit;
    316 
    317   ThreadID := GetCurrentThreadId;
    318   PomList := AxThreads.LockList;
    319   try
    320     for PomIndex := 0 to PomList.Count - 1 do
    321     begin
    322       Result := TAxThread( PomList[ PomIndex ] );
    323       if Result.FThreadID = ThreadID then
    324         Break;
    325       Result := nil;
    326     end;
    327   finally
    328     AxThreads.UnlockList;
    329   end;
    330 end;
    331 
    332 end.
  • 相关阅读:
    Django项目:CRM(客户关系管理系统)--80--70PerfectCRM实现CRM业务流程(bpm)课程排行分页
    Django项目:CRM(客户关系管理系统)--79--69PerfectCRM实现CRM业务流程(bpm)学生讲师分页
    Django项目:CRM(客户关系管理系统)--78--68PerfectCRM实现CRM业务流程(bpm)报名缴费分页
    Django项目:CRM(客户关系管理系统)--77--67PerfectCRM实现CRM课程出勤排名
    Django项目:CRM(客户关系管理系统)--76--66PerfectCRM实现CRM课程作业排名
    mvc 过滤器
    join 和子查询优化
    发布mvc遇到的HTTP错误 403.14-Forbidden解决办法
    获取post传输参数
    iis url 重写
  • 原文地址:https://www.cnblogs.com/shangdawei/p/4011999.html
Copyright © 2011-2022 走看看