2016-08-19 55 views
0

我正在为我的游戏制作修补程序。修补程序使用用户计算机上的本地文件检查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(); 

并在功能结束时检查是否只有1个线程

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

感谢您的帮助家伙!

+0

是的,我的其中一个建议其实:)。顺便说一句,如果threadCount是一个字段,请确保将其标记为“volatile”。 – EJoshuaS

+0

我是否应该让更新文件数量的字段变得不稳定? – DooMLaZyPro

+0

如果你是从多个线程更新它,是的。有可能你可以避免这种情况,只需从“main”函数中进行更新(当然,除非在更新之前确保下载实际上成功)。 – EJoshuaS

1

这取决于;如果你所做的只是印刷一种方法,那么在任何地方都可能并不重要。

但是,如果您希望发生其他事情(或者您将来可能希望发生其他事情),您可以随时举办活动。这实际上是一个相当常见的模式,特别是如果它是一个异步操作(并且它听起来像是它是有意义的,因为它是一个可能长期运行的任务)。

如果您使用的是Task Parallelism,这实际上可以帮助您了解何时完成(至少对于调用者)。

您的其他问题将知道您正在创建的线程何时完成(因为否则即使您将该方法作为一个整体同步运行,它返回的事实并不能保证所有线程都已完成与他们的工作)。当然,这取决于“完成”的含义 - 如果“完成”表示“该方法已将控制权返回给其调用方,并且所有相关的工作都已完成”,或者“该方法已将控制权返回给其调用方呼叫者。” (换句话说,如果它创建的一些线程仍在下载文件,该方法是否可以被认为是“完成”的?如果你指望这些方法在控制权返回给调用者的时候完成,这将是经典的竞赛条件)。

您可以使用Task Parallelism来帮助您了解线程是否完成,如果您愿意的话。另一种(愚蠢但有效的)方法是保持某种变量(以线程安全的方式更新)“正在运行的线程” - 每次生成一个新线程时,都会以线程安全的方式增加计数并且每当他们中的一个完成时,它就减少计数(再次以线程安全的方式)。 (如果你没有使用任务,你也可以考虑使用线程池来执行这些任务,而不是每次都创建一个新的线程)。