简体   繁体   English

如何在Delphi Xe2中创建线程队列?

[英]How do you create a queue of threads in Delphi Xe2?

Have a case where the user may fire off a number of time-consuming jobs that need to be run in the order in which the user does them. 在某些情况下,用户可能会触发许多耗时的工作,这些工作需要按照用户执行工作的顺序运行。

I have been looking at the class TThreadedQueue to store threads. 我一直在看TThreadedQueue类来存储线程。 Is that a good place to start? 那是一个不错的起点吗? Or is there a more appropriate way to do this? 还是有更合适的方法来做到这一点?

below you can find an example of a WorkerThreadPool : 在下面,您可以找到一个WorkerThreadPool的示例:

  {~~~~~~~~~~~~~~~~~~~~~~~~~~~~}
  Twin_WorkerThreadPool = class;

  {~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}
  Twin_WorkerThread = class(TThread)
  private
    FProc: TProc;
    FProcReadySignal: Tevent;
    FProcFinishedSignal: Tevent;
  protected
    procedure Execute; override;
  public
    constructor Create;
    destructor Destroy; override;
    procedure ExecuteAndWaitProc(const AProc: TProc);
    property ProcFinishedSignal: Tevent read FProcFinishedSignal;
  end;

  {~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~}
  Twin_WorkerThreadPool = class(TObject)
  private
    fPool: TObjectList<Twin_WorkerThread>;
    fSignal: Tevent;
  public
    constructor Create(const aThreadCount: integer);
    destructor Destroy; override;
    procedure ExecuteAndWaitProc(const AProc: TProc);
    procedure Enqueue(const Value: Twin_WorkerThread);
    function Dequeue: Twin_WorkerThread;
  end;


{***********************************}
constructor Twin_WorkerThread.Create;
begin
  FProc := nil;
  FProcReadySignal := TEvent.Create(nil, false{ManualReset}, false, '');
  FProcFinishedSignal := TEvent.Create(nil, false{ManualReset}, false, '');
  inherited Create(False); // see http://www.gerixsoft.com/blog/delphi/fixing-symbol-resume-deprecated-warning-delphi-2010
end;

{***********************************}
destructor Twin_WorkerThread.Destroy;
begin
  Terminate;
  FProcReadySignal.setevent;
  WaitFor;
  ALFreeAndNil(FProcReadySignal);
  ALFreeAndNil(FProcFinishedSignal);
  inherited;
end;

{**********************************}
procedure Twin_WorkerThread.Execute;
begin
  while True do begin
    try

      //wait the signal
      FProcReadySignal.WaitFor(INFINITE);

      //if terminated then exit
      if Terminated then Break;

      //execute fProc
      if assigned(FProc) then FProc();

      //signal the proc is finished
      FProcFinishedSignal.SetEvent;

    except
      //hide the exception
    end;
  end;
end;

{*****************************************************************}
procedure Twin_WorkerThread.ExecuteAndWaitProc(const AProc: TProc);
begin
  fProc := AProc;
  FProcFinishedSignal.ResetEvent;
  FProcReadySignal.SetEvent;
  FProcFinishedSignal.WaitFor(INFINITE);
  fProc := nil;
end;

{********************************************************************}
constructor Twin_WorkerThreadPool.Create(const aThreadCount: integer);
var i: integer;
begin
  fPool := TObjectList<Twin_WorkerThread>.create(false{aOwnObjects});
  fSignal := TEvent.Create(nil, true{ManualReset}, false, '');
  for I := 0 to aThreadCount - 1 do
    fPool.Add(Twin_WorkerThread.Create)
end;

{***************************************}
destructor Twin_WorkerThreadPool.Destroy;
var aWorkerThread: Twin_WorkerThread;
    i: integer;
begin
  for I := 0 to fPool.Count - 1 do begin
    aWorkerThread := fPool[i];
    fPool[i] := nil;
    ALFreeAndNil(aWorkerThread);
  end;
  ALFreeAndNil(fPool);
  ALFreeAndNil(fSignal);
  inherited Destroy;
end;

{*********************************************************************}
procedure Twin_WorkerThreadPool.ExecuteAndWaitProc(const AProc: TProc);
var aThread: Twin_WorkerThread;
begin
  aThread := Dequeue;
  try
    aThread.ExecuteAndWaitProc(aProc);
  finally
    Enqueue(aThread);
  end;
end;

{**********************************************************************}
procedure Twin_WorkerThreadPool.Enqueue(const Value: Twin_WorkerThread);
begin
  Tmonitor.Enter(fPool);
  try
    fPool.Add(Value);
    if fPool.Count = 1 then fSignal.SetEvent;
  finally
    Tmonitor.Exit(fPool);
  end;
end;

{********************************************************}
function Twin_WorkerThreadPool.Dequeue: Twin_WorkerThread;
begin
  Tmonitor.Enter(self); // << only one thread can process the code below
  try

    Tmonitor.Enter(fPool);
    try
      if Fpool.Count > 0 then begin
        result := fPool[Fpool.Count - 1];
        fPool.Delete(Fpool.Count - 1);
        exit;
      end;
      fSignal.ResetEvent;
    finally
      Tmonitor.Exit(fPool);
    end;

    while True do begin // << their is a bug on ios with tevent - http://stackoverflow.com/questions/39884521/why-i-get-an-exception-argument-out-of-range
      fSignal.WaitFor(Infinite);
      Tmonitor.Enter(fPool);
      try
        if fPool.Count > 0 then begin
          result := fPool[Fpool.Count - 1];
          fPool.Delete(Fpool.Count - 1);
          exit;
        end
        else begin
          {$IFDEF DEBUG}
          ALLog('Twin_WorkerThreadPool.Dequeue', 'fSignal.ResetEvent didn''t work as expected!', TalLogType.Error);
          {$ENDIF}
        end;
      finally
        Tmonitor.Exit(fPool);
      end;
    end;

  finally
    Tmonitor.exit(self);
  end;
end;

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM