Ignore:
Timestamp:
Jan 26, 2011, 7:12:08 PM (13 years ago)
Author:
george
Message:
  • Moved: Global function with platform depending implementation moved to UPlatform unit.
  • Modifed: Demo form restructuralized to tabs with separate pages.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • MicroThreading/UMicroThreading.pas

    r148 r149  
     1(* Not implemented yet
     2- Stack limit checking
     3- measurement of cpu usage by micro threads
     4- microthread critical sections (no low level cpu blocking)
     5- wait for single and multiple objects
     6- micro thread priorty
     7*)
     8
    19unit UMicroThreading;
    210
     
    715
    816uses
    9   {$IFDEF Windows}Windows,{$ENDIF}
    10   {$IFDEF Linux}BaseUnix, UnixUtil, Unix,{$ENDIF}
    11   Classes, SysUtils, Contnrs, SyncObjs, DateUtils, Dialogs, Forms;
     17  {$IFDEF UNIX}{$IFDEF UseCThreads}
     18  cthreads,
     19  {$ENDIF}{$ENDIF}
     20  Classes, SysUtils, Contnrs, SyncObjs, DateUtils, Dialogs, Forms, UPlatform;
    1221
    1322const
     
    4352    FManager: TMicroThreadManager;
    4453    FId: Integer;
     54    function GetStackUsed: Integer;
    4555  public
    4656    Name: string;
     
    6979    property Scheduler: TMicroThreadScheduler read FScheduler;
    7080    property Manager: TMicroThreadManager read FManager;
     81    property StackUsed: Integer read GetStackUsed;
    7182  end;
    7283
     
    8091  end;
    8192
    82   { TMicroThreadSchedulerPoolThread }
    83 
    84   TMicroThreadSchedulerPoolThread = class(TThread)
     93  { TMicroThreadThread }
     94
     95  TMicroThreadThread = class(TThread)
    8596    Manager: TMicroThreadManager;
    8697    procedure Execute; override;
     
    8899      const StackSize: SizeUInt = DefaultStackSize);
    89100    destructor Destroy; override;
    90   end;
    91 
    92   TThreadPool = class(TObjectList)
    93101  end;
    94102
     
    123131  private
    124132    FActive: Boolean;
    125     FThreadPool: TThreadPool;
     133    FThreadPool: TObjectList;
    126134    FThreadPoolLock: TCriticalSection;
    127135    FThreadPoolSize: Integer;
     
    129137    FLastId: Integer;
    130138    FFrequency: Int64;
    131     FTerminate: Boolean;
    132139    FTerminated: Boolean;
    133140    FMicroThreads: TObjectList; // TList<TMicroThread>
     
    136143    FState: TMicroThreadSchedulerState;
    137144    function GetMicroThreadCount: Integer;
     145    function GetThreadPoolCount: Integer;
    138146    function GetThreadPoolSize: Integer;
    139147    procedure SetActive(const AValue: Boolean);
    140148    procedure SetThreadPoolSize(const AValue: Integer);
    141149    function GetNextMicroThread: TMicroThread;
    142     procedure WaitFor;
    143150    procedure Start;
    144151    procedure Stop;
    145     function ThreadPoolTerminated: Boolean;
     152    procedure PoolThreadTerminated(Sender: TObject);
     153    procedure UpdateThreadPoolSize;
    146154  public
    147     function GetNow: TDateTime;
    148155    function Add(MicroThread: TMicroThread): Integer;
    149156    function AddMethod(Method: TMicroThreadEvent): Integer;
    150     function GetCPUCoreCount: Integer;
    151157    constructor Create;
    152158    destructor Destroy; override;
    153     property MicroThreadCount: Integer read GetMicroThreadCount;
     159    property ThreadPool: TObjectList read FThreadPool;
    154160    property ThreadPoolSize: Integer read GetThreadPoolSize
    155161      write SetThreadPoolSize;
     162    property ThreadPoolCount: Integer read GetThreadPoolCount;
    156163    property MicroThreads: TObjectList read FMicroThreads;
    157164    property MicroThreadsLock: TCriticalSection read FMicroThreadsLock;
     165    property MicroThreadCount: Integer read GetMicroThreadCount;
    158166    property MainThreadManager: TMicroThreadManager read FMainThreadManager;
    159167    property Active: Boolean read FActive write SetActive;
     
    216224  CurrentTime: TDateTime;
    217225begin
    218   CurrentTime := FScheduler.GetNow;
     226  CurrentTime := NowPrecise;
    219227  if Assigned(FCurrentMicroThread) then begin
    220228    FCurrentMicroThread.FExecutionEndTime := CurrentTime;
     
    268276        mov edx, [eax].TMicroThread.FStackPointer
    269277        mov esp, edx
    270         push ebp
     278        push ebp // remember bp on micro thread stack for read back
    271279        mov edx, [eax].TMicroThread.FBasePointer
    272280        mov ebp, edx
     
    336344end;
    337345
    338 { TMicroThreadSchedulerPoolThread }
    339 
    340 procedure TMicroThreadSchedulerPoolThread.Execute;
     346{ TMicroThreadThread }
     347
     348procedure TMicroThreadThread.Execute;
    341349var
    342350  ExecutedCount: Integer;
     
    354362end;
    355363
    356 constructor TMicroThreadSchedulerPoolThread.Create(CreateSuspended: Boolean;
     364constructor TMicroThreadThread.Create(CreateSuspended: Boolean;
    357365  const StackSize: SizeUInt);
    358366begin
     
    361369end;
    362370
    363 destructor TMicroThreadSchedulerPoolThread.Destroy;
     371destructor TMicroThreadThread.Destroy;
    364372begin
    365373  Manager.Free;
     
    377385
    378386{ TMicroThread }
     387
     388function TMicroThread.GetStackUsed: Integer;
     389begin
     390  Result := FStack + FStackSize - FStackPointer;
     391end;
    379392
    380393procedure TMicroThread.Execute;
     
    398411procedure TMicroThread.Sleep(Duration: TDateTime);
    399412begin
    400   FWakeUpTime := FScheduler.GetNow + Duration;
     413  FWakeUpTime := NowPrecise + Duration;
    401414  FState := tsSleeping;
    402415  Yield;
     
    461474{ TMicroThreadScheduler }
    462475
    463 function TMicroThreadScheduler.GetNow: TDateTime;
    464 var
    465   {$IFDEF Linux}T: TimeVal;{$ENDIF}
    466   {$IFDEF Windows}TimerValue: Int64;{$ENDIF}
    467 begin
    468   {$IFDEF Windows}
    469   QueryPerformanceCounter(TimerValue);
    470   //Result := Int64(TimeStampToMSecs(DateTimeToTimeStamp(Now)) * 1000) // an alternative Win32 timebase
    471   Result := TimerValue / FFrequency;
    472   {$ENDIF}
    473 
    474   {$IFDEF Linux}
    475   fpgettimeofday(@t, nil);
    476    // Build a 64 bit microsecond tick from the seconds and microsecond longints
    477   Result := t.tv_sec + t.tv_usec / 1000000;
    478   {$ENDIF}
    479 
    480   Result := (Trunc(Now / OneSecond) + Frac(Result)) * OneSecond;
    481 end;
    482 
    483476function TMicroThreadScheduler.Add(MicroThread: TMicroThread): Integer;
    484477begin
     
    486479  MicroThread.FScheduler := Self;
    487480  MicroThread.FId := FLastId;
    488   Result := FMicroThreads.Add(MicroThread);
     481  try
     482    FMicroThreadsLock.Acquire;
     483    Result := FMicroThreads.Add(MicroThread);
     484  finally
     485    FMicroThreadsLock.Release;
     486  end;
    489487end;
    490488
     
    499497end;
    500498
    501 function TMicroThreadScheduler.GetCPUCoreCount: Integer;
    502 var
    503   SystemInfo: _SYSTEM_INFO;
    504 begin
    505   GetSystemInfo(SystemInfo);
    506   Result := SystemInfo.dwNumberOfProcessors;
    507 end;
    508 
    509499constructor TMicroThreadScheduler.Create;
    510500begin
     
    512502  FMicroThreadsLock := TCriticalSection.Create;
    513503  FMicroThreads := TObjectList.Create;
    514   FThreadPool := TThreadPool.Create;
     504  FThreadPool := TObjectList.Create;
    515505  FThreadPoolLock := TCriticalSection.Create;
    516   {$IFDEF Windows}
    517   QueryPerformanceFrequency(FFrequency);
    518   {$ENDIF}
    519506  FRoundRobinIndex := -1;
    520507  FMainThreadManager := TMicroThreadManager.Create;
     
    538525begin
    539526  FTerminated := False;
    540   FTerminate := False;
    541   for I := 0 to FThreadPool.Count - 1 do
    542     TMicroThreadSchedulerPoolThread(FThreadPool[I]).Start;
     527  UpdateThreadPoolSize;
     528  FState := ssRunning;
    543529  repeat
    544530    Executed := FMainThreadManager.Execute(10);
    545531    Application.ProcessMessages;
    546532    if Executed = 0 then Sleep(1);
    547   until FTerminate;
     533  until FState <> ssRunning;
    548534  FTerminated := True;
    549535end;
     
    553539  I: Integer;
    554540begin
     541  FState := ssTerminating;
    555542  try
    556543    FThreadPoolLock.Acquire;
    557544    for I := 0 to FThreadPool.Count - 1 do begin
    558       TMicroThreadSchedulerPoolThread(FThreadPool[I]).Terminate;
     545      TMicroThreadThread(FThreadPool[I]).Terminate;
    559546    end;
    560547  finally
    561548    FThreadPoolLock.Release;
    562549  end;
    563   FTerminate := True;
    564550
    565551  // Wait for all thread managers to finish
     
    568554    Sleep(1);
    569555  until FTerminated and (ThreadPoolSize = 0);
    570 end;
    571 
    572 function TMicroThreadScheduler.ThreadPoolTerminated: Boolean;
    573 var
    574   I: Integer;
     556  FState := ssStopped;
     557end;
     558
     559procedure TMicroThreadScheduler.PoolThreadTerminated(Sender: TObject);
    575560begin
    576561  try
    577562    FThreadPoolLock.Acquire;
    578     I := 0;
    579     while (I < FThreadPool.Count) and
    580       (TMicroThreadSchedulerPoolThread(FThreadPool[I]).Terminated do
     563    FThreadPool.Delete(FThreadPool.IndexOf(Sender));
    581564  finally
    582565    FThreadPoolLock.Release;
     
    584567end;
    585568
     569procedure TMicroThreadScheduler.UpdateThreadPoolSize;
     570var
     571  NewThread: TMicroThreadThread;
     572begin
     573  try
     574    FThreadPoolLock.Acquire;
     575    if FThreadPoolSize > FThreadPool.Count then begin
     576      FThreadPool.Capacity := FThreadPoolSize;
     577      while FThreadPool.Count < FThreadPoolSize do begin
     578        NewThread := TMicroThreadThread.Create(True);
     579        NewThread.Manager.FScheduler := Self;
     580        NewThread.OnTerminate := PoolThreadTerminated;
     581        ThreadPool.Add(NewThread);
     582        NewThread.Resume;
     583      end;
     584    end else
     585    ThreadPool.Count := FThreadPoolSize;
     586  finally
     587    FThreadPoolLock.Release;
     588  end;
     589end;
     590
    586591function TMicroThreadScheduler.GetNextMicroThread: TMicroThread;
    587592var
     
    589594  CurrentTime: TDateTime;
    590595begin
    591   CurrentTime := GetNow;
     596  CurrentTime := NowPrecise;
    592597  Result := nil;
    593598  try
     
    629634end;
    630635
     636function TMicroThreadScheduler.GetThreadPoolCount: Integer;
     637begin
     638  try
     639    FThreadPoolLock.Acquire;
     640    Result := FThreadPool.Count;
     641  finally
     642    FThreadPoolLock.Release;
     643  end;
     644end;
     645
    631646function TMicroThreadScheduler.GetThreadPoolSize: Integer;
    632647begin
     
    645660var
    646661  I: Integer;
    647   NewThread: TMicroThreadSchedulerPoolThread;
     662  NewThread: TMicroThreadThread;
    648663begin
    649664  FThreadPoolSize := AValue;
    650665  if FState = ssRunning then
    651     SetThreadPoolCount
     666    UpdateThreadPoolSize;
    652667end;
    653668
Note: See TracChangeset for help on using the changeset viewer.