Thread.Join(int)在C#中指定超时后没有查杀线程

时间:2012-04-05 16:52:48

标签: c# winforms multithreading io

在我的Windows窗体应用程序中,我正在尝试测试用户访问远程计算机共享文件夹的能力。我这样做的方式(我确信有更好的方法......但我不知道它们)是检查远程机器上是否存在特定目录(我这样做因为我组织中遇到的防火墙/其他安全限制)。如果用户有权访问共享文件夹,则它会立即返回,但如果没有,则会永久挂起。为了解决这个问题,我将检查放入另一个线程并等待仅1000毫秒,然后确定用户无法命中共享。但是,当我这样做时,它仍然会挂起,就好像它永远不会在同一个线程中运行一样。

是什么让它挂起以及如何解决?我认为它在一个单独的线程中的事实将允许我让线程在后台自己完成

这是我的代码:

bool canHitPath = false;
Thread thread = new Thread(new ThreadStart(() =>
{
    canHitPath = Directory.Exists(compInfo.Path);
}));
thread.Start();
thread.Join(1000);

if (canHitPath == false)
{
    throw new Exception("Cannot hit folder: " + compInfo.Path);
}

编辑:我觉得我应该添加抛出异常 IS HIT 的行。我调试了这个并验证了它...但是,当抛出异常时,那就是我的程序挂起的时候。 (我可能还会补充说,异常是在调用方法中捕获的,我从未在调试器中找到catch语句。)

编辑:所以我找到了这个问题的答案......但我不能选择我的答案作为24小时的答案...所以在那之前......你会有转到以下链接:https://stackoverflow.com/a/10045338/1203288抱歉。

5 个答案:

答案 0 :(得分:3)

您的评论清楚地表明该异常实际上已被抛出并被捕获。因此,代码执行至少超过了此代码,我们无法从代码片段中了解它正在做什么。

你确实犯了一个错误,你忘了将线程的IsBackground属性设置为true。没有它,程序无法终止。哪种方法可以得出结论“它阻塞了!”。如果这个猜测不准确,那么我们需要看到主线程的调用堆栈,以了解它正在做什么。打开非托管调试支持并启用Microsoft Symbol Server,以便我们可以看到整个调用堆栈,而不仅仅是托管部分。

完全不同的方法是使用Ping类来探测服务器。

答案 1 :(得分:2)

我猜这是因为当你打电话时:

canHitInstallPath = Directory.Exists(compInfo.InstallPath);

Exists方法保存了胎面的执行流程(这是一个不间断的调用)。如果它挂起30秒,那么你的线程将等待30秒,直到它有机会检查Thread.Join(1000)是否已经过去。

  

请注意,Thread.Join()方法仅阻塞调用线程(通常是应用程序的主要执行线程),直到线程对象完成。在等待特定的Thread完成执行时,您仍然可以在后台执行其他线程。

来自:

Thread.Join Method (System.Threading)

要考虑的另一件事:只检查文件夹是否存在,如果用户可以读取或写入文件夹,则不会发出任何信息。您最好的选择是尝试写入或读取文件夹的文件。这样,您可以确保用户在该文件夹中具有权限。

修改

在你的情况下,线程只有在等待线程完成时才能做其他事情才有意义。如果你不能,他们的线程根本没有帮助你。

<强> EDIT2

支持我的回答的链接:File Descriptors And Multithreaded Programs

<强> EDIT3

您最好的选择是创建杀手线程。当该线程挂起超过X秒时,该线程将终止该DirectoryExists线程。

答案 2 :(得分:2)

我发现了真正的问题:

属性compInfo.Path正在检查远程文件系统上是否存在目录,以确定远程计算机是否为64位。根据结果​​,它返回不同的值。我试着评论检查并成功执行。这解释了为什么我无法通过抛出异常,我在异常消息中调用compInfo.Path。

但是,我认为我们从“真正的问题”中学到了很多东西:

  1. 我在问题中发布的代码(按原样)完全正常。
  2. thread.Join(int)将在指定的时间间隔后退出,而不管线程是否仍在执行代码。
  3. 正在加入的线程可以运行IO操作(从而占用文件/目录),并且在执行thread.Join(int)时仍会出现所需的结果。
  4. 使用调试器上的“步入”按钮将显示许多内容......甚至是您自己的“可靠”代码。 :)
  5. 感谢大家的帮助,耐心和深思熟虑的投入/见解。

答案 3 :(得分:0)

也许看看Task Parallel Library。 TPL旨在最大限度地提高性能,并可能处理任何问题。虽然这种情况也可能完全矫枉过正。

答案 4 :(得分:0)

Thread.Join是一个阻止调用,它将阻止从调用的线程,直到 on 的线程退出。

你基本上是在创建一个新线程来做后台工作,然后告诉主线程等到它完成。实际上是同步完成的。