簡體   English   中英

同步多個線程

[英]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邏輯分開。 您可以通過幾種不同的方法來做到這一點。

  1. 將您的工作作業放入線程安全的隊列中,例如TThreadList<T>TThreadedQueue<T> 每個線程可以定期檢查隊列,如果有,則拉入下一個可用的作業。

    答:一種變化是使用I / O完成端口作為隊列。 發布職位的IOCP使用PostQueuedCompletionStatus()並讓每個線程使用GetQueuedCompletionResult()接收作業。 這樣,操作系統就可以為您完成所有排隊和提取操作,同時在沒有可用工作時允許線程進入休眠狀態。

  2. 將線程置於休眠狀態的池中。 准備好新作業后,請檢查池。 如果有可用線程,請將其從池中拉出,將作業傳遞給它,然后將其喚醒。 否則,將作業放在線程安全隊列中。 作業完成后,讓該線程檢查隊列。 如果有可用的作業,請將其從隊列中拉出,否則將線程放入輪詢中並使其重新進入睡眠狀態。

無論如何,當一個作業完成處理后,該線程可以使用TThread.Synchronize()TThread.Queue()或您選擇的任何其他線程間通信將作業結果通知主線程。 然后主線程可以根據需要更新UI。

線程絕不應觸摸UI來發現新作業。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM