2016-08-19 2 views
0

나는 내 게임에 대한 패치를 만드는 중입니다. patcher는 ftp 서버에있는 각 파일의 크기를 사용자의 컴퓨터에있는 로컬 파일과 비교하여 검사합니다. 다른 경우, ftp 서버에서 새 파일을 다운로드합니다.재귀 함수가 완료되었는지 확인하는 방법은 무엇입니까?

"업데이트 완료! X 파일이 업데이트되었습니다."라는 인쇄 메시지를 추가하고 싶습니다. 모든 파일을 검사했지만 함수가 어디에서 끝났습니까?

private void CheckForUpdates(string ftpPath, string localPath) 
{ 
    FtpWebRequest request = (FtpWebRequest)WebRequest.Create(ftpPath); 
    request.Credentials = new NetworkCredential(ftpUser, ftpPass); 
    request.Method = WebRequestMethods.Ftp.ListDirectory; 
    FtpWebResponse response = (FtpWebResponse)request.GetResponse(); 
    Stream responseStream = response.GetResponseStream(); 
    StreamReader reader = new StreamReader(responseStream); 

    List<string> files = new List<string>(); 

    string line = reader.ReadLine(); 
    while (!string.IsNullOrEmpty(line)) 
    { 
     if (line != "." && line != ".." && line != ".htaccess") 
     { 
      files.Add(line); 
     } 

     line = reader.ReadLine(); 
    } 

    response.Close(); 
    responseStream.Close(); 
    reader.Close(); 

    foreach (string file in files) 
    { 
     string newFtpPath = ftpPath + "/" + file; 
     string newLocalPath = localPath + "/" + file; 

     new Thread(() => AppendText("Checking " + newLocalPath + Environment.NewLine)).Start(); 

     if (IsFile(newFtpPath)) 
     { 
      if (File.Exists(newLocalPath)) 
      { 
       if (!IsFileEqual(newFtpPath, newLocalPath)) 
       { 
        new Thread(() => AppendText(file + " is out of date or corrupted. Patching in progress..." + Environment.NewLine)).Start(); 
        new Thread(() => Download(newFtpPath, newLocalPath)).Start(); 
       } 
      } 
      else 
      { 
       new Thread(() => AppendText(file + " is missing. Patching in progress..." + Environment.NewLine)).Start(); 
       new Thread(() => Download(newFtpPath, newLocalPath)).Start(); 
      } 
     } 
     else 
     { 
      if (!Directory.Exists(newLocalPath)) 
      { 
       new Thread(() => AppendText(file + " is missing. Patching in progress..." + Environment.NewLine)).Start(); 
       Directory.CreateDirectory(newLocalPath); 
      } 

      new Thread(() => CheckForUpdates(newFtpPath, newLocalPath)).Start(); 
     } 
    } 
} 
+0

메서드를 처음 호출 한 후 알 수 있습니다. 따라서 재귀 함수를 처음 호출 한 후 다음 실행 행. 나는 대개 고정 카운터에 넣어 무기한으로 재발하지 않도록한다. (테스트 할 때) –

+0

여기 당신의 문제는 당신이 새 스레드에서 산란하고 있다는 것이다.나는 확실히 얼마나 많은 쓰레드를 생성하고 세마포어와 같은 것을 사용하는지 추적 할 것입니다. –

+1

이것을 생각한 후에. 필연적으로 스레딩을 통한 재귀를 사용하지는 않을 것이므로 모든 종류의 문제가 첨부되어 상당히 복잡합니다. 나는 단지 플래그와 while 루프를 사용하여 업데이트를 다시 확인해야 할 필요성을 확인합니다. 또는 아마도 –

답변

1

좋아, 그래서 스레드 수를 추가하여 문제를 해결했습니다.

내가보기에 문제는 새로운 스레드를 산산조각 내고 있다는 것입니다. 내가 확실히 내가 파일에 깊이 갈 필요하면 얼마나 많은 스레드를 만들고있는 및 그

을 제어하기 위해 세마포어 같은 것을 사용의 트랙을 유지하는 것입니다 것은 수를

threadCount++; 
new Thread(() => CheckForUpdates(newFtpPath, newLocalPath)).Start(); 

을 스레드에 추가 그리고 함수가 끝나면 스레드가 하나만 있는지 확인하십시오.

if(threadCount == 1) 
    //print end message 
else 
    threadCount--; 

도움 주셔서 감사합니다!

+0

예, 실제로 제 제안 중 하나입니다. BTW threadCount 필드가 "휘발성"으로 표시되어 있는지 확인하십시오. – EJoshuaS

+0

업데이트 된 파일 수의 필드를 휘발성으로 설정해야합니까? – DooMLaZyPro

+0

여러 스레드에서 업데이트하는 경우 예. 물론이를 피할 수는 있지만 "main"함수에서 업데이트 할 수 있습니다 (물론 업데이트하기 전에 다운로드가 실제로 성공했는지 확인하지 않는 한). – EJoshuaS

1

만약 당신이하고있는 모든 일이 한 가지 방법으로 인쇄된다면 그 것이 어디서나 알려지는 것이 중요하지 않을 것입니다.

그러나 다른 일이 일어나기를 원한다면 (또는 앞으로 다른 일이 일어나기를 원할 때) 항상 이벤트를 제기 할 수 있습니다. 이것은 실제로는 매우 일반적인 패턴입니다. 특히 비동기 작업 인 경우 (그리고 오랫동안 실행중인 작업이라는 점을 감안하면 비효율적 인 작업이라고 할 수 있습니다.)

작업 병렬 처리를 사용하는 경우 완료되면 언제든지 (적어도 발신자에게는) 실제로 도움이 될 수 있습니다.

다른 문제는 작성중인 스레드가 완료되었을 때 알 수 있습니다 (그렇지 않으면 메소드를 동 기적으로 실행하더라도 반환 된 사실로 모든 스레드가 완료되었다고 보장 할 수 없기 때문입니다). 그들의 일과 함께). 이것은 물론 "수행하다"로 무엇을 의미 하느냐에 달려 있습니다. "완료"를하면 "메소드가 호출자에게 제어를 돌려 주었고 모든 관련 작업이 완료되었습니다"또는 "이 메소드가 제어를 반환했습니다 방문객." (즉, 만든 스레드 중 일부가 여전히 파일을 다운로드하는 경우 메서드를 "완료"한 것으로 간주 할 수 있습니까? 메서드가 해당 호출자에게 제어권을 반환 할 때까지 완료 될 것으로 예상하는 경우 클래식 경쟁 조건).

작업 병렬 처리를 사용하면 원할 경우 스레드가 완료되었는지 알 수 있습니다. 또 다른 (벙어리지만 효과적 인) 다른 방법은 "쓰레드 안전"방식으로 업데이트되는 일종의 변수를 유지하는 것입니다. 새로운 쓰레드를 생성 할 때마다 쓰레드를 안전한 방식으로 증가시킵니다 그 중 하나가 완료 될 때마다 카운트가 감소합니다 (다시 thread-safe 방식으로). (태스크를 사용하지 않는다면, 매번 새로운 스레드를 생성하는 대신 성능상의 이유 때문에이 태스크를 위해 스레드 풀을 사용할 수도 있습니다).

관련 문제