Ignore:
Timestamp:
Jan 24, 2011, 4:02:40 PM (14 years ago)
Author:
george
Message:
  • Added: Global scheduler MainScheduler for direct access.
  • Added: Similar thread construction as TThread class where Execute is virtual method. Direct adding of method is supported as well.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • MicroThreading/UMicroThreading.pas

    r141 r142  
    1111  Classes, SysUtils, Contnrs, SyncObjs, DateUtils, Dialogs, Forms;
    1212
     13const
     14  DefaultStackSize = $4000;
     15
    1316type
    1417  TMicroThread = class;
    1518  TMicroThreadScheduler = class;
    1619
    17   TStartEvent = procedure(MicroThread: TMicroThread) of object;
    18 
    19   TMicroThreadState = (tsReady, tsRunning, tsWaiting, tsBlocked, tsSuspended,
    20     tsSleeping, tsFinished);
     20  TMicroThreadState = (tsWaiting, tsRunning, tsBlocked, tsSuspended,
     21    tsSleeping);
     22
    2123
    2224  { TMicroThread }
     
    2426  TMicroThread = class
    2527  private
    26     FMethod: TStartEvent;
     28    FFreeOnTerminate: Boolean;
    2729    FStack: Pointer;
    2830    FStackSize: Integer;
     
    3335    FBasePointer: Pointer;
    3436    FWakeupTime: TDateTime;
     37    FTerminated: Boolean;
     38    FExecuted: Boolean; // At first go through Execute method, then switch context
     39    FFinished: Boolean;
    3540  public
    3641    Id: Integer;
     
    3944    State: TMicroThreadState;
    4045    Scheduler: TMicroThreadScheduler;
     46    procedure Execute; virtual;
     47
     48    // Internal execution
    4149    procedure Yield;
    4250    procedure Sleep(Duration: TDateTime);
    43     constructor Create;
     51    function WaitForSignal(Signal: TEvent): TWaitResult;
     52
     53    // External execution
     54    procedure WaitFor;
     55    procedure Terminate;
     56    procedure Start;
     57    procedure Stop;
     58
     59    constructor Create(CreateSuspended: Boolean;
     60      const StackSize: SizeUInt = DefaultStackSize);
    4461    destructor Destroy; override;
    45     property Method: TStartEvent read FMethod write FMethod;
    4662    property ExecutionTime: TDateTime read FExecutionTime;
     63    property FreeOnTerminate: Boolean read FFreeOnTerminate
     64      write FFreeOnTerminate;
     65    property Terminated: Boolean read FTerminated;
     66  end;
     67
     68  TMicroThreadEvent = procedure(MicroThread: TMicroThread) of object;
     69
     70  { TMicroThreadMethod }
     71
     72  TMicroThreadMethod = class(TMicroThread)
     73    Method: TMicroThreadEvent;
     74    procedure Execute; override;
    4775  end;
    4876
     
    5583  TMicroThreadScheduler = class
    5684  private
    57     FFreeMicroThreadOnFinish: Boolean;
    5885    ThreadPool: TThreadPool;
    5986    RoundRobinIndex: Integer;
     
    6794    FExecutedCount: Integer;
    6895    FTerminated: Boolean;
     96    FThreadPoolSize: Integer;
    6997    function GetMicroThreadCount: Integer;
     98    function GetThreadPoolSize: Integer;
     99    procedure SetThreadPoolSize(const AValue: Integer);
    70100    procedure Yield(MicroThread: TMicroThread);
    71101  public
    72102    MicroThreads: TObjectList; // TList<TMicroThread>
    73103    Lock: TCriticalSection;
     104    CurrentMicroThread: TMicroThread;
    74105    function GetNow: TDateTime;
    75     function Add(Name: string; Method: TStartEvent): TMicroThread;
     106    function Add(MicroThread: TMicroThread): Integer;
     107    function AddMethod(Method: TMicroThreadEvent): Integer;
    76108    constructor Create;
    77109    destructor Destroy; override;
     
    80112    procedure Stop;
    81113    property MicroThreadCount: Integer read GetMicroThreadCount;
    82     property FreeMicroThreadOnFinish: Boolean read FFreeMicroThreadOnFinish
    83       write FFreeMicroThreadOnFinish;
    84   end;
     114    property ThreadPoolSize: Integer read GetThreadPoolSize
     115      write SetThreadPoolSize;
     116  end;
     117
     118var
     119  MainScheduler: TMicroThreadScheduler;
    85120
    86121const
    87   MicroThreadStateText: array[TMicroThreadState] of string = ('Ready', 'Running',
    88     'Waiting', 'Blocked', 'Suspended', 'Sleeping', 'Finished');
     122  MicroThreadStateText: array[TMicroThreadState] of string = ('Waiting',
     123    'Running', 'Blocked', 'Suspended', 'Sleeping');
    89124
    90125implementation
    91126
     127{ TMicroThreadMethod }
     128
     129procedure TMicroThreadMethod.Execute;
     130begin
     131  inherited Execute;
     132  Method(Self);
     133end;
     134
    92135
    93136{ TMicroThread }
    94137
     138procedure TMicroThread.Execute;
     139begin
     140
     141end;
     142
    95143procedure TMicroThread.Yield;
    96144begin
    97145  Scheduler.Yield(Self);
     146end;
     147
     148procedure TMicroThread.WaitFor;
     149begin
     150  while not FFinished do begin
     151    Sleep(1);
     152  end;
    98153end;
    99154
     
    105160end;
    106161
    107 constructor TMicroThread.Create;
    108 begin
    109   FStackSize := $10000;
     162function TMicroThread.WaitForSignal(Signal: TEvent): TWaitResult;
     163begin
     164  repeat
     165    Result := Signal.WaitFor(1);
     166    Sleep(1);
     167  until Result <> wrTimeout;
     168end;
     169
     170constructor TMicroThread.Create(CreateSuspended: Boolean;
     171  const StackSize: SizeUInt = DefaultStackSize);
     172begin
     173  FStackSize := StackSize;
    110174  FStack := GetMem(FStackSize);
    111175  FBasePointer := FStack + FStackSize;
    112176  FStackPointer := FBasePointer - 20;
    113177  FExecutionTime := 0;
     178  FTerminated := False;
     179  if CreateSuspended then
     180    State := tsSuspended;
     181  FFreeOnTerminate := True;
     182end;
     183
     184procedure TMicroThread.Terminate;
     185begin
     186  FTerminated := True;
    114187end;
    115188
    116189destructor TMicroThread.Destroy;
    117190begin
     191  Terminate;
     192  WaitFor;
     193  // Microthread is finished, remove it from queue
     194  try
     195    Scheduler.Lock.Acquire;
     196    Scheduler.MicroThreads.Delete(Scheduler.MicroThreads.IndexOf(Self));
     197  finally
     198    Scheduler.Lock.Release;
     199  end;
    118200  FreeMem(FStack);
    119201  inherited Destroy;
     202end;
     203
     204procedure TMicroThread.Start;
     205begin
     206  State := tsWaiting;
     207end;
     208
     209procedure TMicroThread.Stop;
     210begin
     211  State := tsSuspended;
    120212end;
    121213
     
    142234end;
    143235
    144 function TMicroThreadScheduler.Add(Name: string; Method: TStartEvent
    145   ): TMicroThread;
    146 var
    147   NewMicroThread: TMicroThread;
    148 begin
    149   NewMicroThread := TMicroThread.Create;
     236function TMicroThreadScheduler.Add(MicroThread: TMicroThread): Integer;
     237begin
     238  Inc(LastId);
     239  MicroThread.Scheduler := Self;
     240  MicroThread.Id := LastId;
     241  Result := MicroThreads.Add(MicroThread);
     242end;
     243
     244function TMicroThreadScheduler.AddMethod(Method: TMicroThreadEvent): Integer;
     245var
     246  NewMicroThread: TMicroThreadMethod;
     247begin
     248  NewMicroThread := TMicroThreadMethod.Create(False);
     249  NewMicroThread.Method := Method;
    150250  NewMicroThread.Scheduler := Self;
    151   NewMicroThread.Name := Name;
    152   NewMicroThread.Method := Method;
    153   Inc(LastId);
    154   NewMicroThread.Id := LastId;
    155   MicroThreads.Add(NewMicroThread);
     251  Result := Add(NewMicroThread);
    156252end;
    157253
     
    161257  MicroThreads := TObjectList.Create;
    162258  ThreadPool := TThreadPool.Create;
    163   FFreeMicroThreadOnFinish := True;
    164259  {$IFDEF Windows}
    165260  QueryPerformanceFrequency(FFrequency);
     
    235330      mov ebp, edx
    236331    end;
     332    CurrentMicroThread := nil;
    237333  end;
    238334
     
    245341    if RoundRobinIndex >= MicroThreads.Count then
    246342      RoundRobinIndex := 0;
    247     while (I < MicroThreads.Count) and (TMicroThread(MicroThreads[RoundRobinIndex]).State <> tsReady) and
    248 (TMicroThread(MicroThreads[RoundRobinIndex]).State <> tsWaiting) do begin
     343    while (I < MicroThreads.Count) and
     344     (TMicroThread(MicroThreads[RoundRobinIndex]).State <> tsWaiting) do begin
    249345      // WakeUp sleeping threads
    250346      if (TMicroThread(MicroThreads[RoundRobinIndex]).State = tsSleeping) and
     
    268364  if Assigned(FSelected) and (FExecutedCount < FExecuteCount) then begin
    269365    Inc(FExecutedCount);
     366    CurrentMicroThread := FSelected;
    270367    asm
    271368      // Store scheduler stack
     
    276373      mov [eax].TMicroThreadScheduler.FMainBasePointer, edx
    277374    end;
    278     if FSelected.State = tsReady then begin
     375    if not FSelected.FExecuted then begin
     376      FSelected.FExecuted := True;
    279377      FSelected.State := tsRunning;
    280378      FSelected.FExecutionStartTime := Time;
     
    293391        mov ebp, edx
    294392      end;
    295       StaticMicroThread.Method(StaticMicroThread);
     393      StaticMicroThread.Execute;
    296394      //FSelected.Method(FSelected);
    297395      StaticScheduler := StaticMicroThread.Scheduler;
     
    307405      FSelected.FExecutionTime := FSelected.FExecutionTime +
    308406       (FSelected.FExecutionEndTime - FSelected.FExecutionStartTime);
    309       if FFreeMicroThreadOnFinish then begin
    310         // Microthread is finished, remove it from queue
    311         try
    312           Lock.Acquire;
    313           MicroThreads.Delete(MicroThreads.IndexOf(FSelected));
    314         finally
    315           Lock.Release;
    316         end;
    317       end else FSelected.State := tsFinished;
     407      FSelected.FFinished := True;
     408      if FSelected.FFreeOnTerminate then begin
     409        FSelected.Free;
     410      end;;
    318411    end else
    319412    if FSelected.State = tsWaiting then begin
     
    348441end;
    349442
     443function TMicroThreadScheduler.GetThreadPoolSize: Integer;
     444begin
     445  Result := FThreadPoolSize;
     446end;
     447
     448procedure TMicroThreadScheduler.SetThreadPoolSize(const AValue: Integer);
     449begin
     450  FThreadPoolSize := AValue;
     451end;
     452
     453initialization
     454
     455MainScheduler := TMicroThreadScheduler.Create;
     456
     457finalization
     458
     459MainScheduler.Free;
     460
    350461end.
    351462
Note: See TracChangeset for help on using the changeset viewer.