我正在創建一個控制檯應用程序,它需要運行多個線程才能完成任務。我的問題是線程正在一個接一個地運行(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