4

在我的 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 语句。)

4

5 回答 5

3

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

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

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

于 2012-04-05T17:55:10.483 回答
2

I found the real problem:

The property compInfo.Path is doing a check for a directory existence on the remote file system to determine if the remote machine is 64 bit or not. Depending on the results, it returns a different value. I tried commenting out the the check and it executed successfully. This explains why I couldn't get past the throwing of the exception, I call compInfo.Path in the message of the exception.

However, I think we learned a lot from "the real problem":

  1. The code I posted in the question (as is) works perfectly fine.
  2. thread.Join(int) will exit after the specified time interval regardless of the fact that the thread may still be executing code.
  3. The thread being joined CAN be running an IO operation (thus tying up a file/directory) and the desired result will still come about when doing a thread.Join(int).
  4. Using the "step into" button on a debugger will reveal many things...even about your own "solid" code. :)

Thanks everyone for your help, patience, and thoughtful input/insights.

于 2012-04-06T15:04:56.740 回答
2

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

canHitInstallPath = Directory.Exists(compInfo.InstallPath);

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

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

从:

Thread.Join 方法(System.Threading)

要考虑的另一件事:仅检查文件夹是否存在并不能说明用户是否可以读取或将文件写入文件夹。您最好的选择是尝试写入或读取文件夹的文件。这样,您可以确保用户在该文件夹中具有权限。

编辑

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

编辑2

支持我的答案的链接:文件描述符和多线程程序

编辑3

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

于 2012-04-05T17:02:43.063 回答
0

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

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

于 2012-04-05T17:03:01.443 回答
0

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

于 2012-04-05T17:02:07.790 回答