2013-04-25 162 views
0

這是我對這件事的第二個問題,即時通訊有一些麻煩。我只是想創建有限數量的線程(在這種情況下,我想要10個線程),然後每個線程都會在列表中選取一個名稱,並在我的站點中獲取一些數據。delphi中的多線程隊列?

我的系統運行得很好,但我的多線程系統仍然無法=(

-

我試圖張貼LU RD的代碼,但主線程不等待線程完成排隊,只是停止=(

代碼:

uses 
Classes,SyncObjs,Generics.Collections; 

Type 
TMyConsumerItem = class(TThread) 
private 
FQueue : TThreadedQueue<TProc>; 
FSignal : TCountDownEvent; 
protected 
procedure Execute; override; 
public 
constructor Create(aQueue : TThreadedQueue<TProc>; aSignal : TCountdownEvent); 
end; 

constructor TMyConsumerItem.Create(aQueue: TThreadedQueue<TProc>; aSignal : TCountDownEvent); 
begin 
Inherited Create(false); 
Self.FreeOnTerminate := true; 
FQueue := aQueue; 
FSignal := aSignal; 
end; 

procedure TMyConsumerItem.Execute; 
var 
aProc : TProc; 
begin 
try 
repeat 
    FQueue.PopItem(aProc); 
    if not Assigned(aProc) then 
    break; // Drop this thread 
    aProc(); 
until Terminated; 
finally 
    FSignal.Signal; 
end; 
end; 

procedure DoSomeJob(myListItems : TStringList); 
const 
cThreadCount = 10; 
cMyQueueDepth = 100; 
var 
i : Integer; 
aQueue : TThreadedQueue<TProc>; 
aCounter : TCountDownEvent; 
function CaptureJob(const aString : string) : TProc; 
begin 
Result := 
    procedure 
    begin 
    // Do some job with aString 
    end; 
end; 
begin 
aQueue := TThreadedQueue<TProc>.Create(cMyQueueDepth); 
aCounter := TCountDownEvent.Create(cThreadCount); 
try 
for i := 1 to cThreadCount do 
    TMyConsumerItem.Create(aQueue,aCounter); 
for i := 0 to myListItems.Count-1 do begin 
    aQueue.PushItem(CaptureJob(myListItems[i])); 
end; 
finally 
for i := 1 to cThreadCount do 
    aQueue.PushItem(nil); 
aCounter.WaitFor; // Wait for threads to finish 
aCounter.Free; 
aQueue.Free; 
end; 
end; 

我的其他問題:Multi Thread Delphi

使用Delphi XE3的Im。

+0

請添加代碼來演示您的問題。這裏的代碼工作正常。 – 2013-04-25 06:05:18

+0

OmniThreadLibrary同時擁有線程池和無鎖多線程隊列類 – 2013-04-25 10:37:38

+0

@LU RD,問題是主線程在線程完成工作之前只是推零。我真的不知道爲什麼=(.man線程隊列很難做到._。 – Kirito94 2013-04-25 13:54:21

回答

5
  • 首先,如果你想調用程序DoSomeJob()並阻塞,直到主線程準備就緒,這裏有個警告。如果您的工作線程正在與主線程同步,則會出現死鎖情況,其中aCounter.WaitForTThread.Synchronize()

我假設這就是發生在你身上的事情,在這裏猜測。

有一種方法可以解決這個問題,因爲我會在這個答案中顯示。

  • 其次,通常應該由線程池處理工作線程,以避免始終創建/銷燬線程。將您的工作傳遞給線程池,以便在線程中運行並等待所有內容。這可以避免阻塞主線程。 我會保留這一點給你。一旦編寫了框架,線程化將變得更容易。如果這看起來很複雜,請嘗試使用OTL線程框架。

這裏是一個例子,其中主線程可以安全地等待DoSomeJob()。 創建一個匿名線程以等待aCounter發信號。 本示例使用TMemoTButton。只需使用這些組件創建表單並將按鈕OnClick事件連接到ButtonClick方法即可。

unit Unit1; 

interface 

uses 
    Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, 
    System.Classes, Vcl.Graphics, 
    Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls; 

type 
    TForm1 = class(TForm) 
    Button1: TButton; 
    Memo1: TMemo; 
    procedure Button1Click(Sender: TObject); 
    private 
    { Private declarations } 
    procedure DoSomeJob(myListItems : TStringList); 
    public 
    { Public declarations } 
    end; 

var 
    Form1: TForm1; 

implementation 

{$R *.dfm} 

uses 
    SyncObjs, Generics.Collections; 

{- Include TMyConsumerItem class here } 

procedure TForm1.Button1Click(Sender: TObject); 
var 
    aList : TStringList; 
    i : Integer; 
begin 
    aList := TStringList.Create; 
    Screen.Cursor := crHourGlass; 
    try 
    for i := 1 to 20 do aList.Add(IntToStr(i)); 
    DoSomeJob(aList); 
    finally 
    aList.Free; 
    Screen.Cursor := crDefault; 
    end; 
end; 

procedure TForm1.DoSomeJob(myListItems: TStringList); 
const 
    cThreadCount = 10; 
    cMyQueueDepth = 100; 
var 
    i: Integer; 
    aQueue: TThreadedQueue<TProc>; 
    aCounter: TCountDownEvent; 

    function CaptureJob(const aString: string): TProc; 
    begin 
    Result := 
     procedure 
     var 
     i,j : Integer; 
     begin 
     // Do some job with aString 
     for i := 0 to 1000000 do 
      j := i; 
     // Report status to main thread 
     TThread.Synchronize(nil, 
      procedure 
      begin 
      Memo1.Lines.Add('Job with:'+aString+' done.'); 
      end 
     ); 

     end; 
    end; 
var 
    aThread : TThread; 
begin 
    aQueue := TThreadedQueue<TProc>.Create(cMyQueueDepth); 
    aCounter := TCountDownEvent.Create(cThreadCount); 
    try 
    for i := 1 to cThreadCount do 
     TMyConsumerItem.Create(aQueue, aCounter); 
    for i := 0 to myListItems.Count - 1 do 
    begin 
     aQueue.PushItem(CaptureJob(myListItems[i])); 
    end; 
    // Kill the worker threads 
    for i := 1 to cThreadCount do 
     aQueue.PushItem(nil); 
    finally 
    // Since the worker threads synchronizes with the main thread, 
    // we must wait for them in another thread. 
    aThread := TThread.CreateAnonymousThread(
     procedure 
     begin 
     aCounter.WaitFor; // Wait for threads to finish 
     aCounter.Free; 
     aQueue.Free; 
     end 
    ); 
    aThread.FreeOnTerminate := false; 
    aThread.Start; 
    aThread.WaitFor; // Safe to wait for the anonymous thread 
    aThread.Free; 
    end; 
end; 

end. 
+0

我認爲現在可以工作了你說得對,我的工作者線程與主線程同步,當我的web服務器在線時我會測試,大概晚上7點( GMT -3)。 謝謝LU RD =) - 編輯 忘了問,爲什麼CreateAnonymousThread有var i? – Kirito94 2013-04-25 17:37:06

+0

您可以忽略i變量。剩下的我忘了刪除。完成! – 2013-04-25 20:00:12

+0

不工作。也許是我的一個功能導致問題?當我開始這個進程時,10個工作線程正常啓動,但是有些工作線程因爲他們停止了=(。我將檢查我所有的代碼,我認爲現在的問題就是我的代碼。無論如何,謝謝LU RD。 – Kirito94 2013-04-26 14:23:05