views:

422

answers:

5

I have a thread that goes out and attempts to make a connection. In the thread, I make a call to a third party library. Sometimes, this call hangs, and never returns. On the UI thread, I want to be able to cancel the connection attempt by aborting the thread, which should abort the hung call to the third party library.

I've called Thread.Abort, but have now read that Thread.Abort only works when control returns to managed code. I have observed that this is true, because the thread never aborts, and I've been sitting on Thread.Join for ten minutes now. What should I do with this hung thread? Should I just null the reference and move on? I'd like to be as clean as possible--

+1  A: 

Random thought: I wonder if you could write a second assembly as a small console exe that does this communication... launch it with Process.Start and capture results either via the file system or by intercepting stdout. Then if it hangs you can kill the process.

A bit harsh, maybe - and obviously it has overheads of spawning a process - but it should at least be possible to kill it.

Marc Gravell
"Take off and nuke the site from orbit -- it's the only way to be sure." Indeed, you are correct; this is the only guaranteed safe way to terminate misbehaving code. Thread.Abort is not guaranteed to actually abort the misbehaving thread; a truly badly behaved thread can hijack the abort. Even taking down an appdomain doesn't necessarily do what you want. If you absolutely, positively have to kill badly behaved code then you need to isolate it to a killable process.
Eric Lippert
Thanks Ripley... I mean... Eric ;-p (I would have given Hudson's reply, but I'd then have to use the moderator tools on myself...)
Marc Gravell
+1  A: 

Managed threads can't directly stop native threads. So if the call is blocked in native code then the best you can do is have the managed thread check then terminate once it returns. If it never returns, maybe there's a version of the call with a timemout?

If not, killing the thread (through win32) is not usually a good idea...

Arnshea
the call never returns, that's why I have to artificially terminate the thread.
MedicineMan
+1  A: 

This function in your third-party library doesn't have a timeout or cancel function? If so, that's pretty poor design. There's not going to be any pretty solution here, methinks...

Unfortunately, there's no way you're going to get around it, short of using the Win32 API to kill the thread manually, which is certainly not going to be clean. However, if this third-party library is not giving you any other options, it may be the thing to do. The TerminateThread function is what you'll want to use, but observe the warning! To get the thread ID to pass to this function, you have to use another Win32 API call (the Thread class doesn't expose it directly). The approach here will be to set the value of a volatile class variable to the result of GetCurrentThreadId at the start of the managed thread method, and then use this thread ID later to terminate the thread.

Noldorin
A: 

Not sure if this will do it or be acceptable, but its worth a shot.

[DllImport("kernel32.dll")]
private static extern bool TerminateThread (Int32 id, Int32 dwexit);

From the documentation

TerminateThread is a dangerous function that should only be used in the most extreme cases. You should call TerminateThread only if you know exactly what the target thread is doing, and you control all of the code that the target thread could possibly be running at the time of the termination. For example, TerminateThread can result in the following problems:

  • If the target thread owns a critical section, the critical section will not be released.
  • If the target thread is allocating memory from the heap, the heap lock will not be - released.
  • If the target thread is executing certain kernel32 calls when it is terminated, the kernel32 state for the thread's process could be inconsistent.
  • If the target thread is manipulating the global state of a shared DLL, the state of the DLL could be destroyed, affecting other users of the DLL.
Greg Dean
A: 

Not a good solution to ever wait on a thread (in any language) indefinitely, especially if you are making external calls. Always use a join with a timeout, or a spin lock that monitors the state of a shared atomic variable until it changes, or you reach a timeout. I'm not a C# guy, but these are all sound concurrency practices.

Gandalf
did you even read the question
Greg Dean
Sure did - thanks though.
Gandalf