1

안녕하세요. 중요한 섹션에 대해 의문이 생깁니다. 나는 스캐너 스레드에 대한 두 개의 스레드 scannerThread와 scannerchild thread.Code를 가지고있다. Scannerchild에 대한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; 

코드는 내가 출력을 얻고 있지만 직렬화되지 여기

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; 

아래에 언급되어있다. 처음 생성 된 스레드와 같이 먼저 표시되지 않습니다. 내가 192.168.0.10으로 IP 범위 192.168.0.1을 넣으면 그때

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 

처럼오고있다 얻고 있지 않다 내가 비판적 섹션을 사용하지 않기 때문에? 만약 그렇다면, 우선 어디에서 획득하고 임계 영역을 떠나야 만 스레드가 먼저 만들어지며 다음과 같이 다음 섹션으로 들어갈 수 있습니다.

+5

ScannerChild가 VCL 컨트롤을 업데이트하는 것처럼 보입니다. 스레드에서이 작업을 수행 할 수 없습니다. –

+0

사실, 메인 스레드 외부에서 GUI 컨트롤에 액세스 할 수 없습니다. 그 너머의 디자인은 잘못되었습니다. GUI에서 스캐닝 로직을 분리해야한다. –

+0

이 스레드가있는 메인 폼이 없습니다. –

답변

5

스레드는 서로 독립적으로 병렬로 실행됩니다. 스레드간에 동기화 또는 직렬화를 적용하지 않으면 스레드가 작업을 완료하는 순서가 예측할 수 없습니다.

특정 순서로 UI를 업데이트하지 않는 것이 좋습니다. 이렇게하면 검색 성능이 저하되거나 코드가 훨씬 복잡해질 수 있기 때문입니다. 사용자 인터페이스에서

  1. 별도의 스캔 :

    나는 의견의 숫자를해야합니까. 이러한 디자인은보다 깨끗하고 각 측면에 독립적으로 집중할 수 있습니다. 이 작업을 수행하는 방법은 스캔 결과를 비 시각적 구조에 저장 한 다음 GUI가이 구조의보기를 제공하도록 정렬하는 것입니다.

  2. 언제든지 참조가 오래 될 수 있기 때문에 스레드를 시작한 후에는 종료 스레드에 대한 참조를 보유하지 마십시오.
  3. 단일 주소를 처리하는 스레드를 만들지 마십시오. 스레드 풀을 사용하십시오.
  4. 잠자 지 마세요.
  5. 코드 누출이 IpList입니다. finally을 사용하는 방법에 대해 알아보십시오.
0

다른 좋은 조언 이외에도 Tilo Eckert의 UThreadStringList를 살펴볼 것을 권장합니다. 코드는 여기에 게시되고 설명됩니다 : http://www.swissdelphicenter.ch/torry/showcode.php?id=2167 중요한 섹션 잠금이 내장 된 스레드 안전 TStringList입니다. 어떤 TStringlist와 마찬가지로 사용하기 때문에 결과를 모두 채우고 정렬 한 다음 모든 스레드가 완료되면 다시 UI에 할당 할 수 있습니다.
스레드 풀을 구현하려는 경우 UThreadStringList를 작업 대기열로 사용하고 다른 하나를 사용하여 결과를 보관할 수 있습니다.

+0

스레드 안전 문자열 목록에 대해서, Indy는 스레드 안전 문자열 목록, IdThreadSafe 유닛의'TIdThreadSafeStringList' 클래스도 함께 제공합니다. – TLama