2013-04-25 114 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