Sunday, 10 August 2014

Thread Suspend, Resume and Abort

At first sight aborting, suspending or resuming threads (in the .Net arena) seems pretty simple, the Thread class sports methods for each of these 3 tasks. However, if you check the documentation, you'll see that both Suspend and Resume are marked as obsolete and highly discouraged:

Do not use the Suspend and Resume methods to synchronize the activities of threads. You have no way of knowing what code a thread is executing when you suspend it. If you suspend a thread while it holds locks during a security permission evaluation, other threads in the AppDomain might be blocked. If you suspend a thread while it is executing a class constructor, other threads in the AppDomain that attempt to use that class are blocked. Deadlocks can occur very easily.

As for the native Win32 funcion SuspendThread you'll find equally discouraging statements:

This function is primarily designed for use by debuggers. It is not intended to be used for thread synchronization. Calling SuspendThread on a thread that owns a synchronization object, such as a mutex or critical section, can lead to a deadlock if the calling thread tries to obtain a synchronization object owned by a suspended thread. To avoid this situation, a thread within an application that is not a debugger should signal the other thread to suspend itself. The target thread must be designed to watch for this signal and respond appropriately.

Thread.Abort is not marked as obsolete and no advice against its use is explicitly given in MSDN, but you'll find multiple articles and discussions (like this pointing against its use, just for the same reasons as Suspend.

The basic idea is that these methods are too invasive, they'll just Suspend or Abort a thread irrespective of what it's doing at that moment, which can be pretty risky. We need then a more collaborative way to do this, basically a Thread should be periodically stopping to do its main task and checking for Suspend or Abort requests at moments when it can really proceed with such order, aborting/suspending itself accordingly. Obviously the "periodically stop to do its main task" thing can be complicated to accomplish depending on what that main task is... but that's apart from the suspend/abort logic.

For Abort it seems pretty simple. A given thread would just check for an Abort flag, and when true, it would just end.

while(!this.abort){ //check for Abort requests
     DoWork();
}

For Suspend/Resume it's a bit more complicated, we can check for a Suspend flag, but once suspended, how do we check for the Resume order? Well, signals are the main communication mechanism among threads, so we should just use that, a ManuaResetEvent initially set as signaled, we would indicate a Suspend request by resetting it, and then send a Resume command by setting it again.

while(!this.abort){ //check for Abort requests
     DoWork();
     this.resumeSuspend.WaitOne(); //check for Resume/Suspend requests
    }

To really understand it you'll have to see this full sample

No comments:

Post a Comment