2014-09-12 3 views
-2

멀티 스레드 응용 프로그램 (ip 스캐너)에 대해 의문점이 있습니다. 192.168.0.1 192.168.0.1 192.168.0.1 같은 큰 IP 범위 및 스레드 제한을 99로 넣을 때. 그래서 내 응용 프로그램을 실행할 때 (99 스레드 (ScannerChild) + 주 스레드 + Scannerthread) 한 번에 101 스레드를 실행해야하며 스캔 할 때 99 scannerchild와 1 scannethreads가 종료되고 1 스레드 만 그 시간 (메인 스레드)을 실행해야합니다. 하지만 스레드 수가 102로 바뀌고 스캔 스레드 수가 1로 오지 않으면 작업 관리자에서 threadcount가 2로 표시되는 경우가 있습니다. 뭐가 문제 야 ? Scannerthread 에 대한일부 불확실한 스레드가 생성 중이고 종료되지 않습니다.

코드/

/Creating constructor of scannerthread 
Constructor ScannerThread.Create(CreateSuspended: Boolean); 
Begin 
    Inherited Create(CreateSuspended); 
    Freeonterminate:= true; //Freeonterminate is true 
End; 

{ScannerThread Thread } 
procedure ScannerThread.Execute; 
var 
    I : integer; 
    ScannerCh : array of ScannerChild; //array of ScannerChild 
    IpList : TStringlist; //Iplist as tstringlist 
    IPs: Integer; //ipcount is count of iplist 
Begin 
    ScannerchCount:=0; //Initialising scannerchcount as 0 
    IpList:=TStringList.Create;//creating stringlist 
    IF GetNumberOfIpsInRange(Ip_From, Ip_To, IpList) Then //Function call that returns iplist if TRUE 
    Begin 
    Try 
     IF Assigned(LvHosts) Then  //Clearing LvHosts field 
     LvHosts.Clear; 
     IPs := IpList.Count; //Ipcount is given value of iplists count 
     SetLength(ScannerCh, IPs); //Setting length of scannerch as ipcount 

     I:=0; 
     Repeat 
      While ScannerChcount > tcount-1 do //Checking if is greater than tcount(thread input) by user 
      Sleep(30); 
      ScannerCh[I]:=ScannerChild.Create(True, IpList[i]); 
      ScannerCh[I].FreeOnTerminate:=True; 
      ScannerCh[I].OnTerminate:= ScanchildTerminated; // Event scanchildterminated occurs on termination of Scannerch thread 
      ScannerCh[I].LvHostname := LvHosts; //Lhostname is private listview of scannechild 
      ScannerCh[I].Resume; 
      ScannerChCount:=Scannerchcount+1; //Incrementing scannerchcounts 
      I:=I+1; 
      Sleep(20); //Sleep after each thread is created so that threads will enter critical section properly 
     until I = IPs; 

     Scannerch:=nil; 
     If Assigned(IpList) Then //Free iplist 
     FreeAndNil(IpList); 

    Except 
     On E: Exception do 
     Begin 
     ShowMessage('Invalid operation :' + E.Message); //Showexception message 

     If Assigned(IpList) Then   //Free iplist 
     FreeAndNil(IpList); 
     end; 
    End; 
    End 
    Else 
    Begin 
    Ipscan.lbResult.caption:='Invalid Ip Range'; 
    Exit; 
    End; 
    Repeat                  //Main Thread Waiting For Ip scan Threads to finish 
    Sleep(100); 
    until ScannerChCount = 0; 

End; 

Scannerchild 코드

Constructor ScannerChild.Create(CreateSuspended: Boolean; IP: String); 
Begin 
    Inherited Create(CreateSuspended); 
    //FCriticalsection := TCriticalSection.create; //Creating critical section 
    IPToScan:=IP; 
End; 



//Execution procedure for scannerchild 
procedure ScannerChild.Execute; 
Var 
MainOutput : TListItem;//Listitem variable for adding listitems 
Hostname : String; //Hostname is declared as string 
Begin 
Try 
    MainOutput:=LvHostname.Items.Add; //Adding items to mainoutput 
    MainOutput.Caption:=IPToScan; 
    Hostname := IPAddrToName(IPToScan); 
    If Hostname <> EmptyStr Then 
    Begin 
    MainOutput.SubItems.Add(IPAddrToName(IPToScan)); //Displaying output 
    End 
    Else 
    Mainoutput.subitems.add('No host'); 
    Finally 
    End; 

End; 

//this event get called when scannerch thread terminates 
procedure Scannerthread.ScanchildTerminated(Sender : TObject); 
Begin 
    ScannerChCount:=ScannerchCount-1; // Decrementing scannerchcount 

End; 
+0

일부 디버깅을 수행합니다. 닫히지 않을 스레드가 멈추는 부분을 해결할 수있는 진단 코드를 추가하십시오. 디버깅하는 법을 배워야합니다. 그리고 그것은 반드시 디버거에서 의미하는 것은 아닙니다. 추적 디버깅을 추가하십시오. –

+6

그리고 여전히 메인 스레드에서 GUI 컨트롤에 접근하고 있습니다. 여러 번 그 얘기를 들었습니다. 답장을 무시하는 이유는 무엇입니까? 그것은 우리를 괴롭 히고 있습니다. 우리가 너에게 똑같은 말을하고 싶다고 생각하니? 우리는 사람들이 배우는 것을 돕고 보상을 얻습니다. 당신이 듣기가 불가능하다면 우리에게는 보상이 없습니다. 우리의 가치있는 시간을 가지세요. 또한 많은 쓰레드를 만들고 파괴 할 수 있습니다. 100 개의 스레드를 생성하고 완료 될 때까지 작업을 수행하도록하십시오. –

답변

4

여기에 문제의 많음이있다. 귀하의 질문에 답할뿐만 아니라 일반적인 조언을 드릴 것입니다.

앞서 언급했듯이 기본 스레드 외부에서 GUI에 액세스하는 것은 잘못된 것입니다. 다시 그 문제를 다룰 필요가 없습니다. 이전 질문으로 돌아 가세요.

스레딩의 디자인이 좋지 않습니다. 당신이 그것에 대해 고차원적인 질문을한다면 우리는 당신이 그것을 고칠 수 있도록 도울 수 있습니다. 간단한 스레드 풀을 보여줄 수있는 질문을하면 행복 할 것입니다.

스레딩 디자인의 문제뿐만 아니라 걱정거리가 없습니다. 모듈성이 없음. 스레딩과 작업 및 GUI 코드는 모두 서로 섞여 있습니다. 코드를 유지 보수 할 수 있고 잘 분류 할 수 있도록하기 위해 관심사를 분리해야합니다. 우리가 당신을 도울 수있는 약한 디자인의 버그를 고치는 대신 프로그램을 디자인하는 방법을 우리에게 묻는다면.

Sleep에 대한 모든 호출과 폴링은이 나쁜 디자인의 증상입니다. 수면이 없어야합니다.

코드에 너무 많은 설명이있어 읽기가 어렵습니다. i := i+1과 같은 성명을 언급 할 필요가 없습니다. 그 효과는 자명합니다.

스레드 된 코드를 디버깅하는 방법을 배워야합니다. 대화 형 디버거는 그렇게 유용하지 않습니다. 그것은 스레드 실행의 타이밍을 방해합니다. 이러한 문제를 디버그하려면 추적 로깅을 사용하십시오. 이렇게하는 법을 배우기 전까지는 진전을 기대할 수 없습니다. 반복합니다. 디버깅 방법을 배우는 것이 중요합니다.

질문하신 문제에 대해서는 ScannerChCount 변수에 데이터 경쟁이 있습니다. 따라서 스레드가 올바르게 종료 될 수 있지만 잘못 계산하고 있습니다.

InterlockedIncrementInterlockedDecrement을 사용하면 스레드를 안전하게 수정할 수 있습니다. 그것은 자식 종료 코드와 컨트롤러 스레드 모두에 있습니다.

카운터를 감소시키는 ScanChildTerminatedOnTerminate 이벤트이므로 메인 스레드가 실행하므로이 작업이 필요하지 않다고 생각할 수도 있습니다. 그러나 카운터를 증가시키는 컨트롤러 스레드 코드는 주 스레드에서 실행되지 않습니다.

데이터 경주가 무엇인지 아직 모르는 경우에는 멀티 스레드 프로그래밍을 너무 빨리 시작했습니다. 필자가 설명하기보다는 병렬 프로그래밍에 대한 훌륭한 교과서의 공유 데이터 섹션을 참조 할 것입니다. 또는 위키 백과 : http://en.m.wikipedia.org/wiki/Race_condition.

+0

나는 이것을 반드시 지키겠다. –

관련 문제