多线程Delphi [英] Multi Thread Delphi
问题描述
我想创建10个线程,当一些线程终止时,创建另一个...直到结束列表。 / p>
var
Form1:TForm;
tCount:Integer; //线程数
实现
类型
TCheck =类(TThread)
public
构造函数Create(Name:string);
析构函数覆盖;
protected
procedure Execute;覆盖;
结束
MainT = class(TThread)
protected
procedure Execute;覆盖;
结束
析构函数TCheck.Destroy;
begin
Dec(tCount);
结束
程序MainT.Execute;
var
i:整数;
加载:TStringList;
begin
加载:= TStringList.Create;
Load.LoadFromFile('C:\mynames.txt');
for i:= 0 to Load.Count -1 do
begin
如果tCount = 10然后//如果我们有10个线程运行...
开始
重复
睡眠(1);
,直到tCount< 10;
结束
TCheck.Create(Load.Strings [i]);
TCheck.Start;
Inc(tCount);
end;
end; //程序结束
嗯,我没有把TCheck.Constructor放在一起,因为问题是方法我如何检查创建的线程的数量。我的意思是,我的软件停止,没有任何错误信息,有时检查500个名字,有时候150个名字...
对不起英语不好。
这是一个使用泛型的线程安全队列解决方案。
定义你想要的消费者线程,队列深度,并从线程运行 DoSomeJob
过程。
使用字符串定义您的工作一个通用过程(在 CaptureJob
中)。
当队列为空时,消费者线程将被销毁。 DoSomeJob
程序等待所有作业准备就绪。
您可以轻松地将其转换为通用的工作池,重用线程而不会破坏它们。工作项的通用结构也使它们适合于处理不同类型的工作。
请注意,此队列适用于XE2及更高版本。如果您使用的是较旧的delphi版本,请查看注释中建议的类似的线程安全队列。
使用
类,SyncObjs,Genericics.Collections;
键入
TMyConsumerItem = class(TThread)
private
FQueue:TThreadedQueue< TProc> ;;
FSignal:TCountDownEvent;
protected
procedure Execute;覆盖
public
构造函数创建(aQueue:TThreadedQueue< TProc> ;; aSignal:TCountdownEvent);
结束
构造函数TMyConsumerItem.Create(aQueue:TThreadedQueue< TProc>);
begin
Inherited Create(false);
Self.FreeOnTerminate:= true;
FQueue:= aQueue;
FSignal:= aSignal;
结束
程序TMyConsumerItem.Execute;
var
aProc:TProc;
begin
try
repeat
FQueue.PopItem(aProc);
如果没有分配(aProc)然后
break; //放这个线程
aProc();
直到终止;
finally
FSignal.Signal;
结束
结束
程序DoSomeJob(myListItems:TStringList);
const
cThreadCount = 10;
cMyQueueDepth = 100;
var
i:整数;
aQueue:TThreadedQueue< TProc> ;;
aCounter:TCountDownEvent;
函数CaptureJob(const aString:string):TProc;
开始
结果:=
程序
开始
//用aString
结束做一些工作;
结束
begin
aQueue:= TThreadedQueue< TProc> .Create(cMyQueueDepth);
aCounter:= TCountDownEvent.Create(cThreadCount);
尝试
为i:= 1 to cThreadCount do
TMyConsumerItem.Create(aQueue,aCounter);
for i:= 0 to myListItems.Count-1 do begin
aQueue.PushItem(CaptureJob(myListItems [i]));
结束
finally
for i:= 1 to cThreadCount do
aQueue.PushItem(nil);
aCounter.WaitFor; //等待线程完成
aCounter.Free;
aQueue.Free;
结束
结束
NB :Ken解释为什么你的初始化和线程的启动是错误的。这个提议显示出更好的结构,以更通用的方式处理这种类型的问题。
I'm having problems with multi thread in delphi. I Have a list of names (something about 2.000 names), and I need to get some data of each name in my site. My system works perfectly, except the thread control.
I want to create 10 threads, and, when some thread terminate, create another... until end of list.
var
Form1: TForm;
tCount: Integer; //threads count
implementation
type
TCheck = class(TThread)
public
constructor Create(Name: string);
destructor Destroy; Override;
protected
procedure Execute; Override;
end;
MainT = class(TThread)
protected
procedure Execute; Override;
end;
destructor TCheck.Destroy;
begin
Dec(tCount);
end;
procedure MainT.Execute;
var
i: Integer;
Load: TStringList;
begin
Load:=TStringList.Create;
Load.LoadFromFile('C:\mynames.txt');
for i:= 0 to Load.Count -1 do
begin
if tCount = 10 then //if we have 10 threads running...
begin
repeat
Sleep(1);
until tCount < 10;
end;
TCheck.Create(Load.Strings[i]);
TCheck.Start;
Inc(tCount);
end;
end; // end of procedure
Well, I didn't put the TCheck.Constructor because the problem is the method how I'm check the number of created threads. I mean, my software just stop, without any error message, sometimes check 500 names, sometimes 150 names...
Sorry for Bad English.
Here is a threadsafe queue solution using generics.
Define how many consumer threads you want, the queue depth and just run the DoSomeJob
procedure from a thread.
Define your job working with a string as a generic procedure (in CaptureJob
).
When the queue is empty, the consumer threads will be destroyed. The DoSomeJob
procedure waits until all jobs are ready.
You can easily turn this into a generic worker pool, reusing the threads without destroying them. The generic structure of the job items also make them suitable to handle different kinds of work.
Note this queue works on XE2 and above. If you are on a older delphi version, look for a similar threadsafe queue as suggested in comments.
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>);
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;
NB: Ken explains why your initialization and start of threads are wrong. This proposal shows a better structure to handle this type of problems in a more generic way.
这篇关于多线程Delphi的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!