Ignore:
Timestamp:
Feb 9, 2011, 1:35:28 PM (13 years ago)
Author:
george
Message:
  • Modified: Sync functions now not accept main thread context. Instead MainScheduler.AddMethod have to by used.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • MicroThreading/UMicroThreading.pas

    r164 r166  
    3232  SManagerReferenceLost = 'Reference to manager lost';
    3333  SCantDetermineThreadID = 'Can''t determine thread for id %d';
    34   SNotInThread = 'Not in thread';
    35   SReleaseNotAcquiredLock = 'Release not acquired lock';
     34  SNotInMicroThread = 'Not in microthread';
     35  SReleaseNotAcquiredLock = 'Release on not acquired lock';
     36  SMethodNotAssigned = 'Method for microthread not assigned';
    3637
    3738
    3839type
     40  EMicroThreadError = class(Exception);
     41
    3942  TMicroThread = class;
    4043  TMicroThreadScheduler = class;
     
    4346  TMicroThreadState = (tsNone, tsWaiting, tsRunning, tsBlocked, tsSuspended);
    4447  TMicroThreadBlockState = (tbsNone, tbsSleeping, tbsWaitFor, tbsTerminating,
    45     tbsTerminated);
     48    tbsTerminated, tbsCriticalSection);
    4649
    4750  { TMicroThreadCriticalSection }
    4851
    4952  TMicroThreadCriticalSection = class
     53  private
     54    FMicroThreads: TObjectList;
    5055    Lock: TCriticalSection;
    51     Counter: Integer;
     56    FCounter: Integer;
     57  public
    5258    procedure Acquire;
    5359    procedure Release;
     
    111117    procedure Yield;
    112118    procedure MTSleep(Duration: TDateTime); // No conflicting name to global Sleep procedure
     119    procedure WaitForCriticalSection(CriticalSection: TMicroThreadCriticalSection);
    113120    function WaitForEvent(Event: TMicroThreadEvent; Duration: TDateTime): TWaitResult;
    114121    procedure WaitFor;
     
    141148
    142149  TMicroThreadSimple = class(TMicroThread)
    143     Method: TMicroThreadMethod;
     150    Method: TProcedureOfObject;
    144151    procedure Execute; override;
    145152  end;
     
    228235    BurstCount: Integer;
    229236    function Add(MicroThread: TMicroThread): Integer;
    230     function AddMethod(Method: TMicroThreadMethod): Integer;
     237    function AddMethod(Method: TProcedureOfObject; WaitForFinish: Boolean = False): Integer;
    231238    procedure Remove(MicroThread: TMicroThread; Free: Boolean = True);
    232239    constructor Create;
     
    263270    'Running', 'Blocked', 'Suspended');
    264271  MicroThreadBlockStateText: array[TMicroThreadBlockState] of string = ('None',
    265     'Sleeping', 'WaitFor', 'Terminating', 'Terminated');
     272    'Sleeping', 'WaitFor', 'Terminating', 'Terminated', 'CriticalSection');
    266273  MicroThreadThreadStateText: array[TMicroThreadThreadState] of string = (
    267274    'Ready', 'Running', 'Terminated');
     
    294301begin
    295302  MT := GetCurrentMicroThread;
    296   if Assigned(MT) then Result := MT.Id else Result := -1;
     303  if Assigned(MT) then Result := MT.Id
     304    else Result := -1;
    297305end;
    298306
     
    322330  MT := GetCurrentMicroThread;
    323331  if Assigned(MT) then MT.MTSleep(Duration)
    324     else Sleep(Trunc(Duration / OneMillisecond));
     332    else raise EMicroThreadError.Create(SNotInMicroThread);
    325333end;
    326334
     
    332340    Thread := TThreadEx.CurrentThread;
    333341    if Assigned(Thread) then TThread.Synchronize(Thread, Method)
    334       else raise Exception.Create(Format(SCantDetermineThreadID, [GetCurrentThreadId]));
     342      else raise EMicroThreadError.Create(Format(SCantDetermineThreadID, [GetCurrentThreadId]));
    335343  end else Method;
    336344end;
     
    342350  MT := GetCurrentMicroThread;
    343351  if Assigned(MT) then Result := MT.WaitForEvent(Event, Duration)
    344     else begin
    345       while not Event.Signaled do begin
    346         Sleep(1);
    347         Application.ProcessMessages;
    348       end;
    349       //raise Exception.Create(SNotInThread);
    350 //    else Result := Event.WaitFor(Trunc(Duration / OneMillisecond));
    351     end;
     352    else raise EMicroThreadError.Create(SNotInMicroThread);
    352353end;
    353354
     
    374375
    375376procedure TMicroThreadCriticalSection.Acquire;
    376 begin
    377   try
     377var
     378  MT: TMicroThread;
     379  Event: TMicroThreadEvent;
     380begin
     381  MT := GetCurrentMicroThread;
     382  if Assigned(MT) then MT.WaitForCriticalSection(Self)
     383    else raise EMicroThreadError.Create(SNotInMicroThread);
     384end;
     385
     386procedure TMicroThreadCriticalSection.Release;
     387begin
     388  try
     389    MainScheduler.FMicroThreadsLock.Acquire;
    378390    Lock.Acquire;
    379     while Counter > 0 do begin
    380       try
    381         Lock.Release;
    382         MTSleep(1 * OneMillisecond);
    383       finally
    384         Lock.Acquire;
    385       end;
    386     end;
    387     Inc(Counter);
     391    Dec(FCounter);
     392    if FMicroThreads.Count > 0 then begin
     393      // Release one waiting micro thread and lower counter
     394      TMicroThread(FMicroThreads[0]).FState := tsWaiting;
     395      FMicroThreads.Delete(0);
     396    end;
    388397  finally
    389398    Lock.Release;
    390   end;
    391 end;
    392 
    393 procedure TMicroThreadCriticalSection.Release;
    394 begin
    395   try
     399    MainScheduler.FMicroThreadsLock.Release;
     400  end;
     401end;
     402
     403constructor TMicroThreadCriticalSection.Create;
     404begin
     405  Lock := TCriticalSection.Create;
     406  FMicroThreads := TObjectList.Create;
     407  FMicroThreads.OwnsObjects := False;
     408end;
     409
     410destructor TMicroThreadCriticalSection.Destroy;
     411begin
     412  try
     413    MainScheduler.FMicroThreadsLock.Acquire;
    396414    Lock.Acquire;
    397     if Counter > 0 then Dec(Counter)
    398       else raise Exception.Create(SReleaseNotAcquiredLock);
     415
     416    while FMicroThreads.Count > 0 do begin
     417      // Release one waiting micro thread and lower counter
     418      TMicroThread(FMicroThreads[0]).FState := tsWaiting;
     419      FMicroThreads.Delete(0);
     420    end;
    399421  finally
    400422    Lock.Release;
    401   end;
    402 end;
    403 
    404 constructor TMicroThreadCriticalSection.Create;
    405 begin
    406   Lock := TCriticalSection.Create;
    407 end;
    408 
    409 destructor TMicroThreadCriticalSection.Destroy;
    410 begin
    411   Acquire;
     423    MainScheduler.FMicroThreadsLock.Release;
     424  end;
     425  FMicroThreads.Free;
    412426  Lock.Free;
    413427  inherited Destroy;
     
    456470  MT := GetCurrentMicroThread;
    457471  if Assigned(MT) then Result := MT.WaitForEvent(Self, Duration)
    458     else Result := wrSignaled;
     472    else raise EMicroThreadError.Create(SNotInMicroThread);
    459473end;
    460474
     
    689703begin
    690704  inherited Execute;
    691   Method(Self);
     705  if Assigned(Method) then Method
     706    else raise EMicroThreadError.Create(SMethodNotAssigned);
    692707end;
    693708
     
    700715  except
    701716    on E: Exception do
    702       if Assigned(ExceptionHandler) then ExceptionHandler(Self, E);
     717      if Assigned(ExceptionHandler) then
     718        if GetCurrentThreadId = MainThreadID then ExceptionHandler(Self, E)
     719          else ExceptionHandler(TThreadEx.CurrentThread, E);
    703720  end;
    704721  asm
     
    745762procedure TMicroThread.Yield;
    746763begin
    747   if not Assigned(FManager) then
    748     raise Exception.Create(SManagerReferenceLost);
     764//  if not Assigned(FManager) then
     765//    raise EMicroThreadError.Create(SManagerReferenceLost);
    749766  if FStatePending = tsNone then
    750767    FStatePending := tsWaiting;
     
    774791  FStatePending := tsBlocked;
    775792  Yield;
     793end;
     794
     795procedure TMicroThread.WaitForCriticalSection(
     796  CriticalSection: TMicroThreadCriticalSection);
     797begin
     798  try
     799    CriticalSection.Lock.Acquire;
     800    Inc(CriticalSection.FCounter);
     801    if CriticalSection.FCounter > 1 then begin
     802      CriticalSection.FMicroThreads.Add(Self);
     803      FBlockState := tbsCriticalSection;
     804      FStatePending := tsBlocked;
     805      try
     806        CriticalSection.Lock.Release;
     807        Yield;
     808      finally
     809        CriticalSection.Lock.Acquire;
     810      end;
     811    end;
     812  finally
     813    CriticalSection.Lock.Release;
     814  end;
    776815end;
    777816
     
    862901function TMicroThreadScheduler.Add(MicroThread: TMicroThread): Integer;
    863902begin
    864   Inc(FLastId);
    865   MicroThread.FScheduler := Self;
    866   MicroThread.FId := FLastId;
    867903  try
    868904    FMicroThreadsLock.Acquire;
     905    Inc(FLastId);
     906    MicroThread.FScheduler := Self;
     907    MicroThread.FId := FLastId;
    869908    Result := FMicroThreads.Add(MicroThread);
    870909  finally
     
    873912end;
    874913
    875 function TMicroThreadScheduler.AddMethod(Method: TMicroThreadMethod): Integer;
     914function TMicroThreadScheduler.AddMethod(Method: TProcedureOfObject; WaitForFinish: Boolean): Integer;
    876915var
    877916  NewMicroThread: TMicroThreadSimple;
    878 begin
    879   NewMicroThread := TMicroThreadSimple.Create(False);
    880   NewMicroThread.Method := Method;
    881   NewMicroThread.FScheduler := Self;
    882   Result := Add(NewMicroThread);
     917  CurrentMT: TMicroThread;
     918begin
     919  try
     920    NewMicroThread := TMicroThreadSimple.Create(False);
     921    NewMicroThread.Method := Method;
     922    NewMicroThread.FScheduler := Self;
     923    NewMicroThread.FreeOnTerminate := not WaitForFinish;
     924    if WaitForFinish then begin
     925      CurrentMT := GetCurrentMicroThread;
     926      while not ((NewMicroThread.FState = tsBlocked) and
     927      (NewMicroThread.FBlockState = tbsTerminated)) do begin
     928        try
     929          FMicroThreadsLock.Release;
     930          if Assigned(CurrentMT) then CurrentMT.MTSleep(1 * OneMillisecond)
     931          else begin
     932            Sleep(1);
     933            Application.ProcessMessages;
     934          end;
     935        finally
     936          FMicroThreadsLock.Acquire;
     937        end;
     938      end;
     939    end;
     940  finally
     941    if WaitForFinish then NewMicroThread.Free;
     942  end;
    883943end;
    884944
     
    10661126    end;
    10671127    if I < FMicroThreads.Count then begin
    1068       if Assigned(Manager.FCurrentMicroThread) then
    1069         raise Exception.Create(SManagerMicroThreadRunning);
     1128//      if Assigned(Manager.FCurrentMicroThread) then
     1129//        raise EMicroThreadError.Create(SManagerMicroThreadRunning);
    10701130      Selected := TMicroThread(FMicroThreads[FRoundRobinIndex]);
    10711131      Selected.FState := tsRunning;
     
    10801140procedure TMicroThreadScheduler.ReleaseMicroThread(MicroThread: TMicroThread);
    10811141begin
    1082   if not Assigned(MicroThread) then
    1083     raise Exception.Create(SNilThreadReference);
     1142//  if not Assigned(MicroThread) then
     1143//    raise EMicroThreadError.Create(SNilThreadReference);
    10841144  try
    10851145    FMicroThreadsLock.Acquire;
Note: See TracChangeset for help on using the changeset viewer.