3

Recently I worked with an external dll library where I have no influence on it. Under some special circumstances, a method of this third party dll is blocking and never returning.

I tried to work around this issue by executing this method in a new AppDomain. After a custom timeout, I wanted to Unload the AppDomain and kill all this crap ;)

Unfortunately, it does not work - as someone would expect.

After some time it throws CannotUnloadAppDomainException since the blocking method does not allow aborting the thread gracefully.

I depend on using this library and it does not seem that there will be an update soon.

So can I work around this issue, even if it's not best practice? Any bad hack appreciated :)

lazzy_ms
  • 1,169
  • 2
  • 18
  • 40
dasheddot
  • 2,936
  • 4
  • 26
  • 33
  • 1
    why the need for an AppDomain? why not sure run whatever you need to do in a separate thread? if the thread hangs and you want a dirty hack then use `thread.Abort()` – wal Oct 22 '12 at 13:35
  • That was my early approach. But even after calling Abort the thread is not killed, so I speculated that I have more hard killing possibilities on AppDomains – dasheddot Oct 22 '12 at 13:43
  • 1
    @wal Thread.Abort won't work, the only thing that would on a native call would be [`TerminateThread`](http://msdn.microsoft.com/en-us/library/windows/desktop/ms686717%28v=vs.85%29.aspx) and you *really* don't want to call that. See also [How to kill a thread in C# effectively?](http://stackoverflow.com/questions/12468734/how-to-kill-a-thread-in-c-sharp-effectively). You should consider just leaving the thread as a zombie - unless its a long running process or that thread is consuming CPU time it won't do *that* much harm just abandoning it. – Justin Oct 22 '12 at 14:43

3 Answers3

6

An AppDomain cannot typically solve that problem, it's only good to throw away the state of your program. The real issue is that your thread is stuck. In cases like these, calling Thread.Abort() is unlikely to work, it will just get stuck as well. A thread can only be aborted if it is a "alertable wait state", blocking on a CLR synchronization object. Or executing managed code. In a state that the CLR knows how to safely clean up. Most 3rd party code falls over like this when executing unmanaged code, no way to ever clean that up in a safe way. A decisive hint that this is the case is AppDomain.Unload failing to get the job done, it can only unload the AppDomain when it can abort the threads that are executing code in the domain.

The only good alternative is to run that code in a separate process. Which you can kill with Process.Kill(). Windows do the cleanup. You'd use a .NET interop mechanism to talk to that code. Like named pipes, sockets, remoting or WCF. Plus the considerable hassle of having to write the code that can detect the timeout, kills the process, starts it back up and recovers internal state since you now restart with an uninitialized instance of that 3rd party code.

Do not forget about the real fix. Create a small repro project that reproduces the problem. When it hangs, create a minidump of the process. Send both to the 3rd party support group.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • Thanks for your explanation. I didn't want to use processes since its a ASP.NET app which can be deployed to multiple server. So I would have to hassle with rights. Furthermore I have to call this external method several times and hosting it in a seperate process will definitely not boost the performance, since it is already not as fast as I would like. Anyhow it seems to be the only solution (that I can do), so I may give it a try. Thanks for your help! – dasheddot Oct 23 '12 at 05:48
3

after reading this (scroll down the end to Blocking Issues) I think your only solution is to run the method in a different process - this might involve quite a bit of refactoring and/or a 'host' project (eg Console application) that loads the method in question and makes it easy to call (eg reading args from command line) when launching the new process using the Process class

wal
  • 17,409
  • 8
  • 74
  • 109
1

You can always use background worker, no need to create a new appdomain. This will ensure that you have complete control over the execution of the thread.

However, there is no way to ensure that you can gracefully abort the thread. As the dll is unmanaged, chances are there that it may cause memory leaks. However, spawning a new thread will ensure that your application does not crash when the Dll does not respond.

Murtuza Kabul
  • 6,438
  • 6
  • 27
  • 34