1

Здравствуйте, я сомневаюсь в критическом разделе. У меня есть два потока scannerThread и threader scannerchild.Code для Scannerthread упоминается ниже.Критический раздел в многопоточности для ip-сканера

procedure ScannerThread.Execute; 
var 
    I: Integer; 
    ScannerCh: Array of ScannerChild; 
    IpList: TStringlist; 
    IPCount: Integer; 
begin 
    IpList:=TStringList.Create; 
    IF GetNumberOfIpsInRange(Ip_From, Ip_To, IpList) then // Function call that returns iplist if TRUE 
    begin 
    Try 
     if Assigned(LvHosts) then // Clear 
     LvHosts.Clear; 
     IPCount := IpList.Count; 
     SetLength(ScannerCh, IPCount); 
     I := 0; 
     repeat 
      while GetTThreadsCount(GetCurrentProcessId) > tcount do // Tcount is threads to create which is given by user  
      Sleep(10); 
      ScannerCh[I]:=ScannerChild.Create(True, IpList[i]); 
      ScannerCh[I].FreeOnTerminate := True; 
      ScannerCh[I].LvHostname := LvHosts; 
      ScannerCh[I].Resume; 
      Inc(I); 
     until I = IPCount; 
     if Assigned(IpList) Then 
     FreeAndNil(IpList); 
    except 
     ShowMessage('Operation Failed'); 
     If Assigned(IpList) Then 
     FreeAndNil(IpList); 
    end; 
    end else 
    ShowMessage('Invalid Range'); 
    repeat 
    Sleep(100); 
    Until GetTThreadsCount(GetCurrentProcessId) = 2; 

end; 

Код для Scannerchild упоминается ниже

procedure ScannerChild.AddToList; 
begin 
    ListItems1 := LVHostName.Items.Add; 
    ListItems1.Caption := IPToScan; 
    ListItems1.SubItems.Add(IPAddrToName(IPToScan)); 
end; 

procedure ScannerChild.AddToList1; 
begin 
    ListItems1:=LVHostName.Items.Add; 
    ListItems1.Caption := IPToScan; 
    ListItems1.SubItems.Add('No host found'); 
end; 

procedure ScannerChild.Execute; 
Var 
    ListItems1 : TListItem; 
    Hostname : String; 
begin  
    Hostname := IPAddrToName(IPToScan); 
    if Hostname <> EmptyStr then 
    begin 
     Synchronize(AddToList); 
    end else 
     synchronize(AddToList1); 
end; 

Здесь я получаю выход, но это не сериализации. Как нить, которая создается сначала, сначала не отображается. если я ставлю диапазон IP 192.168.0.1 до 192.168.0.10, то я должен получить сериализованную выход в ListView как

192.168.0.1  hostname 
192.168.0.2  hostname 
192.168.0.3  hostname 
. 
. 
192.168.0.10 hostname 

Но я не получаю it.my выход приходит как

192.168.0.1 hostname 
    192.168.0.2 hostname 
    192.168.0.4 hostname 
    192.168.0.6 hostname 
    192.168.0.3 hostname 

Так это потому что я не использую критический раздел? Nnd, если да, где я должен приобретать и покидать критический раздел, чтобы сначала созданный поток мог входить в критический раздел сначала и следующий поток следующим образом.

+5

Похоже, ScannerChild обновляет элемент управления VCL. Вы не можете сделать это в потоке. –

+0

Действительно, вы не можете получить доступ к элементам управления графическим интерфейсом вне основного потока. Кроме того, ваш дизайн не так. Вам действительно нужно отделить логику сканирования от графического интерфейса. –

+0

nope есть основная форма, у которой есть эти темы –

ответ

5

Резьбы выполняются параллельно, независимо друг от друга. Если вы не навязываете какую-либо синхронизацию или сериализацию между потоками, порядок, в котором они выполняют свои задачи, непредсказуем.

Я предлагаю вам не пытаться обновлять пользовательский интерфейс в определенном порядке, потому что это либо помешает производительности вашего сканирования, либо сделает ваш код намного сложнее.

У меня есть ряд замечаний:

  1. Раздельное сканирование из пользовательского интерфейса. Такая конструкция более чистая и позволяет вам сконцентрироваться на каждом аспекте независимо. Способ сделать это - сохранить результаты сканирования в невизуальной структуре, а затем организовать, чтобы графический интерфейс представлял представление об этой структуре.
  2. Не задерживайте ссылки на свободные при завершении потоков после того, как вы запустили поток, потому что ссылка может быть устаревшей в любое время.
  3. Не создавать потоки для обработки одного адреса. Используйте пул потоков.
  4. Не спите.
  5. Ваш код утечки IpList. Узнайте, как использовать finally.
0

В дополнение к другим полезным советам здесь я рекомендую вам посмотреть на UThreadStringList by Tilo Eckert. Код размещен и объяснен здесь: http://www.swissdelphicenter.ch/torry/showcode.php?id=2167 Это потокобезопасный TStringList с встроенными встроенными замками. Вы используете его точно так же, как и любой TStringlist, чтобы вы могли просто вложить в него все свои результаты, затем сортировать, а затем назначать обратно в свой интерфейс, когда все потоки выполняются.
Если вы хотите реализовать пул потоков, у вас может быть один UThreadStringList, который будет действовать как рабочая очередь, а затем другой, чтобы удерживать результаты.

+0

О потоковом безопасном списке строк, Indy также поставляется с потоковым безопасным строковым списком, классом 'TIdThreadSafeStringList' из модуля IdThreadSafe. – TLama

Смежные вопросы