[英]Synchronize multiple threads
我正在嘗試在Delphi XE5中創建一個多線程應用程序(最多可以說100個線程),所有線程都將使用/更改主窗體中的列表框,這是我的代碼:主機:
private
//list to hold the dynamic created threads
SendThreads : TObjectList;
public
mutex : boolean;
...
procedure TMainForm.FormCreate(Sender: TObject);
begin
...
mutex := false;
SendThreads := TObjectList.Create;
end;
...
//Button to create and start the threads
procedure TMainForm.btnWorkClick(Sender: TObject);
var
Thread : TSendThread;
i, nbr : integer;
begin
if SendThreads.Count < spnThreadCount.Value then
begin
for I := 1 to spnThreadCount.Value - SendThreads.Count do
begin
nbr := SendThreads.Add(TSendThread.Create(true));
Thread := TSendThread(SendThreads.Items[nbr]);
Thread.FreeOnTerminate := true;
Thread.Start;
end;
end;
end;
螺紋單位:
uses MainUnit;
procedure TSendThread.Execute;
begin
QueryList;
end;
//Basically, this procedure checks if the item in the listbox contains '- Done.' which means that this
//item has been done by another thread, if not, the current thread deal with this item.
procedure TSendThread.QueryList;
var i : integer;
S : String;
begin
i := 0;
while i < MainForm.lstURL.Count do
begin
while MainForm.mutex do;
MainForm.mutex := true;
if pos(' - Done.', MainForm.lstURL.Items[i]) = 0 then
begin
S := MainForm.lstURL.Items[i];
Delete(S, 1, pos('?txt=', S) + length('?txt=') - 1);
MainForm.Memo1.Lines.Add(MainForm.lstURL.Items[i]);
MainForm.lstURL.Items[i] := MainForm.lstURL.Items[i] + ' - Done.';
MainForm.mutex := false;
SendAd(URL, S);
end
else
begin
Inc(i);
MainForm.mutex := false;
end;
end;
end;
如果線程數少於4,則此方法有效,但是如果線程數更多,則會得到冗余結果(2個或更多線程執行相同的項目)。 現在我對線程和多線程還很陌生,我想知道這是否是正確的方法。
除了Ken所說的關於UI安全性的內容外,由於mutex
變量上存在競爭條件,因此您正在使線程處理同一項目。 多個線程可能同時看到mutex=false
,因為它們實際上並未與每個otber同步。 您需要使用真正的互斥鎖。 看一下TMutex
類。 或者只是將大部分代碼包裝在TThread.Synchronize()
然后讓VCL為您處理同步。 但這隨后破壞了使用線程的目的。
您正在使用完全錯誤的設計來滿足您的要求。 您需要將工作線程邏輯與UI邏輯分開。 您可以通過幾種不同的方法來做到這一點。
將您的工作作業放入線程安全的隊列中,例如TThreadList<T>
或TThreadedQueue<T>
。 每個線程可以定期檢查隊列,如果有,則拉入下一個可用的作業。
答:一種變化是使用I / O完成端口作為隊列。 發布職位的IOCP使用PostQueuedCompletionStatus()
並讓每個線程使用GetQueuedCompletionResult()
接收作業。 這樣,操作系統就可以為您完成所有排隊和提取操作,同時在沒有可用工作時允許線程進入休眠狀態。
將線程置於休眠狀態的池中。 准備好新作業后,請檢查池。 如果有可用線程,請將其從池中拉出,將作業傳遞給它,然后將其喚醒。 否則,將作業放在線程安全隊列中。 作業完成后,讓該線程檢查隊列。 如果有可用的作業,請將其從隊列中拉出,否則將線程放入輪詢中並使其重新進入睡眠狀態。
無論如何,當一個作業完成處理后,該線程可以使用TThread.Synchronize()
, TThread.Queue()
或您選擇的任何其他線程間通信將作業結果通知主線程。 然后主線程可以根據需要更新UI。
線程絕不應觸摸UI來發現新作業。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.