2010-12-09 20 views
5

這個問題涉及到Delphi和XE特別反對Suspend和Resume。我已經閱讀過其他文章,到目前爲止我還沒有找到類似的用法,所以我會繼續討論。當Delphi不需要並且安全地恢復時,在Delphi中自行掛起一個線程

我想知道有什麼更好的方法來暫停一個線程時,它不需要?

我們有一個Delphi類,我們已經使用了多年,基本上它是一個與線程進程相關聯的FIFO隊列。隊列接受主線程上的數據對象,並且如果線程被掛起,它將恢復它。

作爲線程的Execute進程的一部分,該對象被彈出隊列並在線程上處理。通常這是做一個數據庫查找。

在進程結束時,對象的屬性被更新並標記爲可用於主線程或傳遞到另一個隊列。執行過程的最後一步(也就是它的第一步)是檢查隊列中是否還有其他項目。如果它繼續存在,否則它會暫停。

它們的關鍵是唯一掛起的動作是在Execute循環中完成時的,當正常操作期間的唯一恢復被稱爲新的項目放入隊列時。例外情況是隊列類正在被終止。

恢復功能看起來像這樣。

process TthrdQueue.MyResume(); 
    begin 
    if Suspended then begin 
     Sleep(1); //Allow thread to suspend if it is in the process of suspending 
     Resume(); 
    end; 
    end; 

的執行類似於這樣

process TthrdQueue.Execute(); 
    var 
    Obj : TMyObject; 
    begin 
    inherited; 
    FreeOnTerminate := true; 
    while not terminated do begin 
     if not Queue.Empty then begin 
     Obj := Pop(); 
     MyProcess(Obj); //Do work 
     Obj.Ready := true; 
     end 
     else 
     Suspend(); // No more Work 
    end; //Queue clean up in Destructor 
    end; 

的TthrdQueue推入堆棧增加另一個對象後,程序調用MyResume。如果線程暫停,MyResume只會調用Resume。

當關閉時,我們將終止設置爲true,並在掛起時調用MyResume。

+0

我不是專家,但我只是簡單地使用Sleep(250)或SignalObjectAndWait(請參閱msdn)進行更精確的控制。 – 2010-12-09 18:04:50

回答

5

我建議以下實現TthrdQueue的:

type 
    TthrdQueue = class(TThread) 
    private 
    FEvent: THandle; 
    protected 
    procedure Execute; override; 
    public 
    procedure MyResume; 
    end; 

implementation 

procedure TthrdQueue.MyResume; 
begin 
    SetEvent(FEvent); 
end; 

procedure TthrdQueue.Execute; 
begin 
    FEvent:= CreateEvent(nil, 
         False, // auto reset 
         False, // initial state = not signaled 
         nil); 
    FreeOnTerminate := true; 
    try 
    while not Terminated do begin 
     if not Queue.Empty then begin 
     Obj := Pop(); 
     MyProcess(Obj); //Do work 
     Obj.Ready := true; 
     end 
     else 
     WaitForSingleObject(FEvent, INFINITE); // No more Work 
    end; 
    finally 
    CloseHandle(FEvent); 
    end; 
end; 
+2

他提到他在Delphi XE上,所以他已經可以在Generics.Collections單元中訪問TThreadedQueue泛型類。 TThreadedQueue是一個FIFO隊列,具有在推送和彈出時同步線程的能力。 – vcldeveloper 2010-12-09 20:45:24

+1

我們仍然支持我們庫中的很多Delphi 7代碼。但我會在未來的嘗試中考慮TThreadedQueue。我喜歡給定的解決方案,因爲它更容易更新我們現有的代碼。 – 2010-12-10 14:14:13

3

相反掛起線程,讓它睡覺。使它在一些可等待的手柄上阻塞,並且當手柄變成信號時,線將醒來。

對於等待對象有很多選項,包括事件,互斥對象,信號量,消息隊列,管道。

假設您選擇使用事件。使其成爲自動重置事件。當隊列爲空時,調用事件的WaitFor方法。當其他人填充隊列或想要退出時,讓它調用事件的SetEvent方法。

我首選的技術是使用OS消息隊列。我會用消息替換你的隊列對象。然後,編寫一個標準的GetMessage循環。當隊列爲空時,它將自動阻塞以等待新消息。將終止請求轉換爲另一條消息。 (一旦你開始做線程有趣的事情,TThread.Terminate方法根本不是一個非常有用的函數,因爲它不是虛擬的。)

3

有一個庫允許在Delphi using condition variables中實現生產者 - 消費者隊列。這種情況實際上是討論的例子。

條件 變量的典型示例是生產者/消費者 問題。稱爲 的一個或多個線程生產者生產物品並將其添加到隊列 。消費者(其他線程) 通過從隊列中刪除產生的 項來消耗項目。

相關問題