C# Join(int)在C中指定的超时后不终止线程#

C# Join(int)在C中指定的超时后不终止线程#,c#,multithreading,winforms,C#,Multithreading,Winforms,在我的windows窗体应用程序中,我试图测试用户访问远程计算机共享文件夹的能力。我这样做的方式(我确信有更好的方式……但我不知道它们)是检查远程机器上是否存在特定目录(我这样做是因为我在组织中遇到防火墙/其他安全限制)。如果用户有权访问共享文件夹,那么它将立即返回,但如果用户没有权限,它将永远挂起。为了解决这个问题,我将检查抛到另一个线程中,只等待1000毫秒,然后确定用户无法访问该共享。然而,当我这样做时,它仍然挂起,好像从来没有在同一个线程中运行过一样 是什么让它挂起以及如何修复它?我认为

在我的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);
}

Edit:我觉得我应该补充一点,抛出异常的那一行被击中了。我已经对此进行了调试并进行了验证……但是,当抛出异常时,我的程序就会挂起。(我还可以补充一点,异常是在调用方法中捕获的,我从来没有在调试器中找到catch语句。)

也许可以看一下。TPL旨在最大限度地提高性能,可以处理任何问题。不过,对于这种情况来说,这也可能是完全过火了。

我猜这种情况会发生,因为当你打电话时:

canHitInstallPath = Directory.Exists(compInfo.InstallPath);
Exists
方法保存tread的执行流(它是一个不间断的调用)。如果挂起30秒,您的线程将等待30秒,直到有机会检查
thread.Join(1000)
是否已过期

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

发件人:

另一件需要考虑的事情是:仅检查文件夹是否存在,不会告诉用户是否可以读取或写入文件夹中的文件。最好的选择是尝试写入或读取文件夹的文件。这样,您可以确保用户在该文件夹中拥有权限

编辑

在您的情况下,只有当您在等待线程完成时可以做其他事情时,线程才有意义。如果你做不到,这些线根本帮不了你

EDIT2

支持我答案的链接:

EDIT3


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

Thread.Join
是一个阻塞调用,它将从阻塞它被调用的线程,直到它在上被调用的线程退出


您基本上是在旋转一个新线程来做后台工作,然后告诉主线程等待它完成。实际上,这一切都是同步进行的。

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

您确实犯了一个错误,忘记将线程的IsBackground属性设置为true。没有它,程序无法终止。这是一种你可以得出“它被阻塞了”结论的方式。如果这个猜测不准确,那么我们需要查看主线程的调用堆栈来了解它在做什么。最好通过启用非托管调试支持并启用Microsoft Symbol Server来捕获,这样我们就可以看到整个调用堆栈,而不仅仅是其中的托管部分


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

我发现了真正的问题:

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

然而,我认为我们从“真正的问题”中学到了很多:

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

    是的,我一开始也是这么想的。但是他使用的是需要超时的
    Thread.Join()
    重载,因此至少行为是不直观的。
    Thread.Join(1000)
    将在一秒钟后返回。不管线程在做什么,它都会在一秒钟后杀死线程。它的阻塞时间不应该超过这个时间-我刚刚复制粘贴了这个代码,并将
    Exists
    Thread.Sleep(30000)
    交换,它只阻塞了一秒钟。不确定OP的情况有什么问题…@J..:说真的,它会在超时后杀死线程吗?我在文档中没有看到任何关于这方面的参考。@J..:另外,
    Sleep
    是一个可中断的等待,而OP遇到的问题是一个不可中断的IO等待。它们根本不是一回事。好吧,这是必然的