5

I have a file transport application that moves files between FTP servers. As any one time we can have dozens of files on the move. In order to prevent flooding the FTP servers I have a system of monitor and semaphore locks.

Every so often my FTP client freezes somewhere inside System.Net.Sockets.Socket.Receive() according to the call stack. I don't get an exception so can't deal with the problem. I'd like to cancel the thread as it is blocking other threads that want to use the FTP client.

I've considered starting the method that eventually calls System.Net.Sockets.Socket.Receive() in a new thread and aborting the thread after a time period but I'm concerned that the sockets will remain open after a thread abort. Is there a more gracefull way to kill and clean up after a non responsive thread?

Richard210363
  • 8,342
  • 6
  • 37
  • 63

3 Answers3

4

No. There's no safe, reliable way to kill a thread without its cooperation. The mechanisms that exist can be quite heavy-handed, and/or just don't necessarily work.

  • You can attempt to Interrupt() the other thread, but that generally only interrupts a thread that's waiting/sleeping or is doing something that could block. If it's in the middle of something that doesn't involve blocking, it won't even see, much less respond to, the interrupt til it tries to block again. Which, if you have a rogue thread, may very well be "never".
  • Abort() will probably kill a thread, but it is not guaranteed either -- the thread can stubbornly refuse to die. And even if it does die, it can leave your app domain in a questionable state. (Suppose the thread is aborted just as it entered a finally block. An exception will be thrown right then and there, and that finally block won't run -- so anything it'd release (locks, native resources, whatever) will remain unreleased.)
  • Apparently even unloading the app domain just aborts the threads in it, so the uncertainties of Thread.Abort apply -- plus, if it works, it'll also kill every thread in the app domain.
  • About the only thing that's relatively safe and guaranteed to work is to kill the entire process. And if you do that, there's no guarantee about the state of external stuff. You can just guarantee that any resources held will be released/closed/whatever, not that they're in any particular state (like, say, "uncorrupted").

In this case, a better solution might be to receive asynchronously (using the real async stuff (ReceiveAsync), not BeginReceive/EndReceive). That way the thread isn't blocked in native stuff, and is more easily interruptible (if for some reason you still have to do that; async's benefits include that you don't even need a separate thread just to watch input).

cHao
  • 84,970
  • 20
  • 145
  • 172
  • "real async" as in .NET 4.5 (Visual Studio 2012) and ReceiveAsync? There's nothing to cancel that either... – Peter Ritchie Aug 03 '12 at 15:01
  • @Peter: There's not much to cancel. `ReceiveAsync` returns immediately, and when the data's received, the callback you specified is run. The thread's not blocking on anything. You can easily say in your callback "if i'm disposed or something, don't do anything". – cHao Aug 03 '12 at 15:02
  • I think I misread your post as suggesting using ReceiveAsync is easier to cancel, not that using an asynchronous method would potentially alleviate the need to cancel... – Peter Ritchie Aug 03 '12 at 15:08
2

Have you looked at setting the ReceiveTimeout?

Otherwise, you can setup a Watchdog property in each thread and check the status of the Watchdog variable to identify non-responsive threads.

Ryan
  • 7,835
  • 2
  • 29
  • 36
  • I don't have access to the Socket.ReceiveTimeout property as it's on the far side of an FTPClient dll. My problem is not identifying the non responsive threads, though a Watchdog is a good technique. It's what to do once I have identified the non responsive threads. – Richard210363 Aug 03 '12 at 15:01
  • There is no good way to terminate the threads if it is stuck in `Socket.Receive()`. It will most likely leave your program in an unstable state. Is it a commercial or 3rd party FTPClient dll? – Ryan Aug 03 '12 at 15:06
  • I'm using System.Net.FtpClient from CodePlex as it was recommended. – Richard210363 Aug 03 '12 at 15:25
  • 1
    According to this page http://netftp.codeplex.com/discussions/273132/ there should be a `ReadTimeout` and `WriteTimeout`, as well as async `BeginConnect()`/`EndConnect()` methods. Hopefully it will help. – Ryan Aug 03 '12 at 15:52
0

I would suggest running your thread in a separate process (if possible) and kill it mercilessly. Then OS will release all resources

Roman Saveljev
  • 2,544
  • 1
  • 21
  • 20