2016-11-07 44 views
0

有一種情況,用戶可能會觸發一些耗時的作業,這些作業需要按照用戶的操作順序執行。如何在Delphi Xe2中創建一個線程隊列?

我一直在尋找類TThreadedQueue來存儲線程。這是一個開始的好地方嗎?還是有更合適的方法來做到這一點?

+0

如果只有一個生產者輸入作業,並且作業必須按順序調用一個新的作業無法啓動,直到前準備好,隊列不需要是線程安全的。作業完成後,只需在主線程中觸發一個事件即可啓動隊列中的下一個作業。 –

+3

爲什麼要存儲線程。存儲任務。有一個線程可以逐一完成新的任務。 –

回答

-1

下面你可以找到一個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; 
+0

感謝您的代碼。我去編譯它,發現一個編譯器錯誤。 ALFreeAndNil從哪裏來?它有什麼作用? –

+0

aah對不起alfreeandnil來自alcinoe(你可以在網上找到代碼)...... alfreeandnil完全像freeandnil一樣,除了它使用dispose而不是免費來避免內存泄漏 – loki