我正在创建一个控制台应用程序,它需要运行多个线程才能完成任务。我的问题是线程正在一个接一个地运行(thread1开始 - >工作 - >结束,然后才开始thread2),而不是在同一时间运行所有线程。此外,我不希望超过10个线程同时工作(性能问题)。 Bellow是控制台应用程序和使用的数据模块的示例代码。我的应用程序正在以同样的方式工作。我已经使用了一个datamodule,因为线程完成后,我必须用这些信息填充数据库。在代码中也有注释,说明哪些是做某事的原因。为什么线程在这个控制台应用程序中连续运行?
应用控制台代码:
program Project2;
{$APPTYPE CONSOLE}
uses
SysUtils,
Unit1 in 'Unit1.pas' {DataModule1: TDataModule};
var dm:TDataModule1;
begin
dm:=TDataModule1.Create(nil);
try
dm.execute;
finally
FreeAndNil(dm);
end;
end.
和数据模块代码
unit Unit1;
interface
uses
SysUtils, Classes, SyncObjs, Windows, Forms;
var FCritical: TRTLCriticalSection;//accessing the global variables
type
TTestThread = class(TThread)
protected
procedure Execute;override;
end;
TDataModule1 = class(TDataModule)
procedure DataModuleCreate(Sender: TObject);
procedure DataModuleDestroy(Sender: TObject);
private
{ Déclarations privées }
public
procedure execute;
procedure CreateThread();
procedure Onterminatethrd(Sender: TObject);
end;
var
DataModule1 : TDataModule1;
FthreadCount : Integer; //know how many threads are running
implementation
{$R *.dfm}
{ TTestThread }
procedure TTestThread.Execute;
var
f : TextFile;
i : integer;
begin
EnterCriticalSection(fcritical);
AssignFile(f, 'd:\a' + inttostr(FthreadCount) + '.txt');
LeaveCriticalSection(fcritical);
Rewrite(f);
try
i := 0;
while i <= 1000000 do // do some work...
Inc(i);
Writeln(f, 'done');
finally
CloseFile(f);
end;
end;
{ TDataModule1 }
procedure TDataModule1.CreateThread;
var
aThrd : TTestThread;
begin
aThrd := TTestThread.Create(True);
aThrd.FreeOnTerminate := True;
EnterCriticalSection(fcritical);
Inc(FthreadCount);
LeaveCriticalSection(fcritical);
aThrd.OnTerminate:=Onterminatethrd;
try
aThrd.Resume;
except
FreeAndNil(aThrd);
end;
end;
procedure TDataModule1.Onterminatethrd(Sender: TObject);
begin
EnterCriticalSection(fcritical);
Dec(FthreadCount);
LeaveCriticalSection(fcritical);
end;
procedure TDataModule1.DataModuleCreate(Sender: TObject);
begin
InitializeCriticalSection(fcritical);
end;
procedure TDataModule1.DataModuleDestroy(Sender: TObject);
begin
DeleteCriticalSection(fcritical);
end;
procedure TDataModule1.execute;
var
i : integer;
begin
i := 0;
while i < 1000 do
begin
while (FthreadCount = 10) do
Application.ProcessMessages;//wait for an thread to finish. max threads at a //time =10
CreateThread;
EnterCriticalSection(fcritical);
Inc(i);
LeaveCriticalSection(fcritical);
while FthreadCount > 0 do //wait for all threads to finish in order to close the //main thread
begin
Application.ProcessMessages;
CheckSynchronize;
end;
end;
end;
end.
所以,正如我所说的问题是,我的线程正在运行一个接一个,而不是工作都在同时。我也看到有时只有第一个线程工作,其余的只是创建和完成。在我的应用程序中,所有代码都受到try-excepts的保护,但不会引发错误。
有人可以给我一个建议吗?
确保一次运行不超过10个线程的好方法是使用* semaphore *。在创建线程之前获取它,并让每个线程在终止时释放它。如果已经有10个线程在运行,那么获取信号量的第11次尝试将被阻塞,直到另一个线程终止。那么你不需要那些ProcessMessages忙等待循环。那些循环什么也不做,只是吃掉CPU时间,因为你的应用程序永远不会发送任何消息,所以永远不会有任何东西需要处理。 – 2010-06-27 16:26:11
您可以采取的另一个步骤是只有在实际需要进行同步时调用“CheckSynchronize”。设置信号量后,调用信号量句柄上的MsgWaitForMultipleObjects和全局'SyncEvent'变量。在Classes.pas中阅读它。如果信号量发出信号,则创建一个新线程。如果事件发出信号,请调用CheckSynchronize。 – 2010-06-27 16:32:21
罗布,非常感谢您的信息。 我已经阅读了关于信号量,但我不知道我完全理解我应该如何实现它。从我读过的东西我需要使用WaitForSingleObject(句柄,无限) - 为线程完成整个周期,但我怎么知道什么时候开始另一个线程? 我见过一些例子,所以我相信我必须创建10个线程的信号量,但是当减少我如何创建一个新的线程并在信号量中进行午餐时? 有人可以根据我的例子给我一个小例子吗? 在此先感谢! – RBA 2010-06-28 06:44:16