Delphi中的多线程队列? [英] Multithread queue in delphi?
问题描述
这是我的第二个问题,我对此有一些麻烦。<
This is my second question about this, im having some troubles with this >.<
我只想创建有限数量的线程(在在这种情况下,我需要10个线程),然后每个线程都会在列表中选择一个名称,并在我的网站中获取一些数据。
Well, I just want to create a limited number of threads (in this case, I want 10 threads), and then each thread will pick up a name in my list and get some data in my site.
我的系统运行良好,但是我的多线程系统仍然失败=(
My system works pretty well, but my multi thread system still fails =(
-
我尝试了LU RD发布的代码,但是主线程不等待线程完成队列,而是停止=(
I tried the code posted by LU RD, but the main thread don't wait the threads finish the queue, and just stops =(
代码:
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;
我的另一个问题:多线程Delphi
Im使用Delphi XE3。
Im using Delphi XE3.
推荐答案
- 首先,如果要调用过程
DoSomeJob()
并阻塞直到从主线程准备好,有一个警告。如果您的工作线程正在与主线程同步,则aCounter.WaitFor
和TThread.Synchronize()$会出现死锁情况。 c $ c>。
- First, if you want to call the procedure
DoSomeJob()
and block until ready from the main thread, there is a caveat. If your worker threads are synchronizing with the main thread, there is a dead-lock situation withaCounter.WaitFor
andTThread.Synchronize()
. - 第二,通常是工人线程应由线程池处理,以避免始终创建/销毁线程。将您的工作传递到线程池,以便所有内容在线程内运行并等待。这样可以避免阻塞主线程。
我会留给你。一旦编写了该框架,线程将变得更加容易。如果这看起来很复杂,请尝试使用OTL
线程框架。 - Second, normally the worker threads should be handled by a thread pool, to avoid create/destroy threads all the time. Pass your job to the thread pool, so everything is run and waited for inside a thread. This avoids blocking the main thread.
I will leave this up to you. Once that framework is written, threading will be easier. If this seems complex, try
OTL
threading framework instead.
我以为这是发生在您身上的事情,在这里猜测。
I am assuming that this is what is happening to you, guessing here.
有一种方法可以解决这个问题,正如我在此答案中所展示的。
There is a way to handle that as I will show in this answer.
这里是一个示例,其中主线程可以等待 DoSomeJob()
以安全的方式。
创建了一个匿名线程来等待 aCounter
发出信号。
本示例使用 TMemo
和 TButton
。只需使用这些组件创建一个表单,然后将按钮 OnClick
事件连接到 ButtonClick
方法。
Here is an example where the main thread can wait for DoSomeJob()
in a safe manner.
An anonymous thread is created to wait for the aCounter
to signal.
This example uses a TMemo
and a TButton
. Just create a form with these components and connect the button OnClick
event to the ButtonClick
method.
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.
这篇关于Delphi中的多线程队列?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!