bsara
bsara

Reputation: 8249

Thread.Join(int) not killing thread after specified timeout in C#

In my windows form application, I'm trying to test the user's ability to access a remote machine's shared folder. The way I'm doing this (and I'm sure that there are better ways...but I don't know of them) is to check for the existence of a specific directory on the remote machine (I'm doing this because of firewall/other security restrictions that I'm confronted with in my organization). If the user has rights to access the shared folder, then it returns in no time at all, but if they don't, it hangs forever. To solve this, I threw the check into another thread and wait only 1000 milliseconds before determining that the share can't be hit by the user. However, when I do this, it still hangs as if it was never run in the same thread.

What is making it hang and how do I fix it? I would think that the fact that it is in a separate thread would allow me to just let the thread finish on it's own in the background.

Here is my code:

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: I feel that I should add that the line of throwing the exception IS HIT. I've debugged this and verified it...however, when the exception is thrown, then is when my program hangs. (I might also add that the exception is caught in the calling method and I never get to the catch statement in the debugger.)

Upvotes: 4

Views: 5528

Answers (5)

bsara
bsara

Reputation: 8249

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.

Upvotes: 2

Hans Passant
Hans Passant

Reputation: 942040

Your comments make it clear that the exception is actually thrown and caught. So code execution progressed at least past this code and we can't tell from the snippet what it is doing.

You did make one mistake, you forgot to set the thread's IsBackground property to true. Without it, the program can't terminate. Which is one way you might conclude "it's blocking!". If this guess isn't accurate then we'll need to see the main thread's call stack to have an idea what it is doing. Best captured by turning on unmanaged debugging support and enabling the Microsoft Symbol Server so we can see the entire call stack, not just the managed parts of it.

A completely different approach is to use the Ping class to probe the server.

Upvotes: 3

Rafael Colucci
Rafael Colucci

Reputation: 6078

My guess will be that this happens because when you call:

canHitInstallPath = Directory.Exists(compInfo.InstallPath);

The Exists method holds the execution flow of the tread (it is an uninterruptible call). If it hangs for 30 seconds, them your thread will be waiting for 30 seconds until it has a chance to check if Thread.Join(1000) has elapsed.

Note that the Thread.Join() method only blocks the calling thread (usually the application's main thread of execution) until your thread object completes. You can still have other threads executing in the background while waiting for your specific Thread to finish executing.

From:

Thread.Join Method (System.Threading)

Another thing to consider: Only checking if a folder exists tells nothing if the user can read or write files to the folder. Your best option is to try to write or read a file of the folder. This way you can make sure that the user has permissions in that folder.

EDIT

In you case threads only make sense if you can do other things while waiting for the thread to finish. If you cant, them threads are not helping you at all.

EDIT2

A link to support my answer: File Descriptors And Multithreaded Programs

EDIT3

You best option is to create a killer thread. This thread will kill the DirectoryExists thread when it hangs for more that X seconds.

Upvotes: 2

Bradley Uffner
Bradley Uffner

Reputation: 16991

Thread.Join is a blocking call that will hold up the thread it was called from until the thread it was called on exits.

You are basically spinning up a new thread to do background work, and then telling the main thread to wait until it finishes. In effect doing it all synchronously.

Upvotes: 0

richk
richk

Reputation: 416

Maybe take a look at the Task Parallel Library. The TPL is designed to maximize performance and might handle whatever the issue might be. Though it also might be complete overkill for the situation.

Upvotes: 0

Related Questions