作者热门文章
- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我在 delphi 中遇到多线程问题。我有一个姓名列表(大约 2000 个姓名),我需要获取网站中每个姓名的一些数据。除了线程控制之外,我的系统运行良好。
我想创建 10 个线程,并且当某个线程终止时,创建另一个...直到列表末尾。
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
嗯,我没有放置 TCheck.Constructor,因为问题是我检查创建的线程数的方法。我的意思是,我的软件就停止了,没有任何错误消息,有时检查 500 个名称,有时检查 150 个名称...
抱歉英语不好。
最佳答案
这是一个使用泛型的线程安全队列解决方案。
定义您想要的消费者线程数量、队列深度,然后从线程运行 DoSomeJob
过程。
将使用字符串的作业定义为通用过程(在 CaptureJob
中)。
当队列为空时,消费者线程将被销毁。 DoSomeJob
过程等待所有作业准备就绪。您可以轻松地将其转变为通用工作池,重用线程而不破坏它们。工作项目的通用结构也使它们适合处理不同类型的工作。
请注意,此队列适用于 XE2 及更高版本。如果您使用的是较旧的 delphi 版本,请按照注释中的建议查找类似的线程安全队列。
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;
<小时/>
注意:Ken 解释了为什么你的初始化和线程启动是错误的。该提案展示了一种更好的结构,可以以更通用的方式处理此类问题。
关于multithreading - 多线程德尔福,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15622261/
我是一名优秀的程序员,十分优秀!