‘System.Threading.Thread.Suspend()’ is obsolete: ‘Thread.Suspend has been deprecated…

For time eternal there has been a way to suspend (and by association resume) another thread.  It wasn't until .NET 2.0 that someone took leadership and conceded that suspending another thread is not a safe thing to do.  .NET 2.0 deprecates System.Threading.Thread.Suspend() and Resume() (although, Resume() isn't dangerous by association…).

Basically, Suspend() has no care that the thread may actually be managing one or more complex invariants that can't be changed atomically.  Normally with complex invariants synchronization is used to ensure while one thread is modifying the individual components of an invariant another thread doesn't try to access it.  This is important because the validity of an invariant is rarely atomic; meaning changing an invariant may take several steps and may be in an unknown or invalid state between the first and the last step (a date is a good example, setting the day and month is two steps; until both steps are complete the date might be invalid).  Suspending a thread circumvents the synchronization primitives and cuts the thread off at the knees.

On a lower level, a thread may be performing a system-wide-synchronized operation like locking a range of bytes in a file, writing to those bytes, unlocking those bytes, then closing the file.  If a thread is suspended before the unlock, that range of bytes will remain locked for an indeterminate amount of time until the thread is resumed or the process terminates.  Not a good thing.  Most threads don't do all their work with low-level methods and call various higher-level helper methods to perform tasks.  This means the author of a thread's routine really has no way to determine whether their thread is in a "suspendable" state at any given point in time.  .NET complicates this even further by using locks during execution of class constructors–increasing the likelihood that suspending a thread will cause dire consequences.

Unfortunately, the documentation for Thread.Suspend() really doesn't offer much in the way of guidance on how to get around this issue with your own threads, it just casually mentions classes Monitor, Mutex, Event and Semaphore; but doesn't offer any detail on how to use them to put your thread into a wait state–the equivalent of Suspend.

When I create threads they're meant simply to let my UI be responsive or make use of multiple CPUs (i.e. in both cases they're CPU bound) and don't have much need to put a thread into a wait state manually.  But, it's not without merit.  There are lots of circumstances I don't normally get into that could benefit from being able to put a thread into a wait state.  It's also a common question; so, the following is small class that I created: SuspendableThread.

namespace PRI.Threading

{

    using System.Threading;

    abstract class SuspendableThread

    {

        #region Data

        private ManualResetEvent suspendChangedEvent = new ManualResetEvent(false);

        private ManualResetEvent terminateEvent = new ManualResetEvent(false);

        private long suspended;

        private Thread thread;

        private System.Threading.ThreadState failsafeThreadState = System.Threading.ThreadState.Unstarted;

        #endregion Data

 

        public SuspendableThread ( )

        {

        }

 

        private void ThreadEntry ( )

        {

            failsafeThreadState = System.Threading.ThreadState.Stopped;

            OnDoWork();

        }

 

        protected abstract void OnDoWork ( );

 

        #region Protected methods

        protected Boolean SuspendIfNeeded ( )

        {

            Boolean suspendEventChanged = suspendChangedEvent.WaitOne(0, true);

            if (suspendEventChanged)

            {

                Boolean needToSuspend = Interlocked.Read(ref suspended) != 0;

                suspendChangedEvent.Reset();

                if (needToSuspend)

                {

                    /// Suspending…

                    if (1 == WaitHandle.WaitAny(new WaitHandle[] { suspendChangedEvent, terminateEvent }))

                    {

                        return true;

                    }

                    /// …Waking

                }

            }

            return false;

        }

 

        protected bool HasTerminateRequest ( )

        {

            return terminateEvent.WaitOne(0, true);

        }

        #endregion Protected methods

 

        public void Start ( )

        {

            thread = new Thread(new ThreadStart(ThreadEntry));

 

            // make sure this thread won't be automaticaly

            // terminated by the runtime when the

            // application exits

            thread.IsBackground = false;

 

            thread.Start();

        }

 

        public void Join ( )

        {

            if (thread != null)

            {

                thread.Join();

            }

        }

 

        public Boolean Join ( Int32 milliseconds )

        {

            if (thread != null)

            {

                return thread.Join(milliseconds);

            }

            return true;

        }

 

        /// <remarks>Not supported in .NET Compact Framework</remarks>

        public Boolean Join ( TimeSpan timeSpan )

        {

            if (thread != null)

            {

                return thread.Join(timeSpan);

            }

            return true;

        }

 

        public void Terminate ( )

        {

            terminateEvent.Set();

        }

 

        public void TerminateAndWait ( )

        {

            terminateEvent.Set();

            thread.Join();

        }

 

        public void Suspend ( )

        {

            while (1 != Interlocked.Exchange(ref suspended, 1))

            {

            }

            suspendChangedEvent.Set();

        }

 

        public void Resume ( )

        {

            while (0 != Interlocked.Exchange(ref suspended, 0))

            {

            }

            suspendChangedEvent.Set();

        }

 

        public System.Threading.ThreadState ThreadState

        {

            get

            {

                if (null != thread)

                {

                    return thread.ThreadState;

                }

                return failsafeThreadState;

            }

        }

    }

} // namespace

This thread class works a little differently than the run-time's System.Threading.Thread class in that you can't just pass it a method from any-old place.  Because we don't want just anyone getting at the implementation details used to suspend the thread, you have to derive from SuspendableThread and override OnDoWork so your code can gain access to helper methods.

This class has another feature.  If you're likely to want to initiate thread suspension externally, you're likely to want to initiate thread termination externally as well.  To that effect this thread also has Terminate() and TerminateAndWait() methods that ask the thread to terminate and will awaken the thread is suspended (something System.Thread.Suspend() and System.Thread.Abort() won't do).

Using this class is fairly simple.  If you want a suspendable/terminatable thread you simply create a new SuspendableThread-derived class and override OnDoWork with the following pattern:

class MyThread : PRI.Threading.SuspendableThread

{

    protected override void OnDoWork ( )

    {

        try

        {

            while (false == HasTerminateRequest())

            {

                Boolean awokenByTerminate = SuspendIfNeeded();

                if (awokenByTerminate)

                {

                    return;

                }

 

                // TODO: replace the following to lines

                Debug.WriteLine("doing some work…");

                Thread.Sleep(450);

            }

        }

        finally

        {

            // TODO: Replace the following line with thread

            // exit processing.

            Debug.WriteLine("Exiting ThreadEntry()…");

        }

    }

}

For this class to be useful you generally have to have an iterative algorithm that can test for suspend/terminate during each iteration (the while loop in the above pattern).

To initiate thread suspension, simply call the SuspendableThread.Suspend() method–which asynchronously suspend the thread.  SuspendableThread.Resume() resumes the thread.  For terminate, generally you want to be able to determine when the thread has terminated.  If you want to do that asynchronously  you use the SuspendableThread.Terminate() and SuspendableThread.Join() methods.  To start the terminate process Terminate() is called.  When your asynchronous work is done (i.e. you went on to do something else while the thread was terminating) call Join() to block until the thread is terminated.  If you don't need to, or don't have anything to, do while the thread is terminating, use SuspendThread.TerminateAndWait().

This class gives complete control of suspension and termination to the thread.  So, use this class with great care.  You have to write your OnDoWork override in a way that won't cause deadlocks.  If you don't have an iterative process, this class isn't for you.  If each of your iterations takes much time (more than say 500ms) then this class probably isn't for you either.  If you can't terminate in the middle of your process, this class also is not for you.  This class will not let the application terminate until the thread routine has exited; so, be sure you initiate termination of the thread before the application exits or you'll get a deadlock.  The class is a scaled-down version of System.Threading.Thread.  It doesn't provide all the same goodies System.Threading.Thread does (partially for .NET Compact Framework 2.0 support, and partially for readability) and is intended to be used in limited scenarios.  But, you can extend it to mirror some of System.Threading.Thread's functionality fairly easily–like Name and Priority properties.

This class was intentionally designed to be compatible with the .NET CF 2.0 (delete Join(TimeSpan) before compiling) but has not been tested with .NET CF 2.0 (if you use the class in .NET CF 2.0, please send me a note and I'll update this post for the benefit of other readers).

[30-Oct-06 Update: as it turns out, this class is not entirely .NET CF 2.0 compatible, please contact me if you're interested in a .NET CF 2.0 compatible version]

44 thoughts on “‘System.Threading.Thread.Suspend()’ is obsolete: ‘Thread.Suspend has been deprecated…

  1. Hello.

    Nice forum design. Okay, I need your help.
    So, I wanna make online-store, and I am looking for site template.
    Can you advice some online place or other resource where I can find many site templates?

    It would be better if it will be free:)
    I think many of us have personal sites, do you design it yourself?

    Thanks a lot, Bill.

  2. Arun, what scenario are you referring to? BackgroundWorker is excellent for running time-consuming processing in the background so it doesn’t affect the user interface. While BackgroundWorker supports cancellation, your processing has to poll whether the cancel flag has been set while it’s processing.

  3. Interesting idea and implementation. However, by declaring it as abstract, it makes it harder to use since the class that I want to do the work in already has a base class. What to do? Since C# only allows single inheritance, the only practical solution I see is to remove the abstract keyword from the SuspendableThread class, use composition, and call the methods directly from my class. Do you see any problems with this?

  4. Peter,
    I have build up a windows server, which does some file processing using multiple threads. Now there is a situation, where in I need to call the Stop() & Start(), which doesnt effect the windows service as such, but internally its like restarting the service. During this process I need to terminate all the active threads. My code to terminate the thread in the Stop() is similar to this:
    if (Thread.CurrentThread.ManagedThreadId != workerThread.ManagedThreadId)
    {
    try
    {
    // Signal the thread.
    // Try to join the main thread with a timeout of 2sec
    while (!workerThread.Join(2000))
    {
    // Awake any sleeping thread
    waitHandler.Set();
    }
    }
    catch (ThreadStateException tex)
    {
    tex.Message;
    }
    }

    Now, how do i ensure the thread have terminated properly, so that I can recreate new set of threads in the Start() method. I think currently my threads have gone to the WaitSleepJoin state and will get awakned any time.

  5. Vikram, I’d likely have to see more code to judge what would be the most appropriate answer. But, from your code you appear to be attempting to wait for the thread to exit (by calling Join) then signalling the thread to exit (via the call to Set) if the Join times out after 2 seconds. Join is the only reliable way to be informed of a thread exiting (polling IsAlive is problematic and introduces latency). I’m assuming the worker thread is either performing work or waiting on waitHandler. I would call waitHandler.Set before calling Join; but I would only call it once–I see no reason to repeatedly call Set.

    You’ll only get the ThreadStateException if the worker thread hasn’t been started. You’ll also get a ThreadInterruptedException if the thread is interrupted while Join is waiting for the thread to exit–which sometimes occurs upon application shutdown if at thread hasn’t exited.

  6. Thanks Peter,
    Yes, I want the workerthread to come to a known end.
    I wrote the waitHandler.Set within the loop to cater a scenario where the workerthread goes to “waitsleepjoin”, between the waithandler.Set and workerthread.Join() call or rather after the ‘set’ and before ‘join’.
    And I used ANTS profiler to see if my threads actually terminates and ends. And am happy to see it does once the GC runs.

  7. @Vikram. Unless the thread terminates itself between the first Join and the Set call, you’re guaranteed to halt for 2 seconds.

    If the thread goes into a waitsleepjoin after you call Set, there’s not much you can do without calling Interrupt. The thread will still see the Set when it next waits for that event; setting it again won’t make a difference. It will only make a difference if the event is an auto reset and something else is waiting on the event as well–which is not a good thing; the event should be only used for termination of the thread.

  8. First off – Great work Peter. I am wondering if you could suggest some in my situation. I have a GUI app which needs to be very responsive and it depends upon the data that come in files, so I created a background thread that runs infinitely and pooling files that got parse and displayed on the GUI. Since the GUI is dynamic and can change what file should be pooled now I want to suspend and resume that backgroud thread – this is where I think I could use your class. In the mean time I tried to use Thread.Abort but sometimes it does not finishes the thread. Also even I shutdown the main GUI the thread since dangles and appear in the Task Manager. The thread property Isbackground is set to true. What am I missing?

  9. Any chance you could explain why the while loop wrapping the Interlocked.Exchange calls in the Suspend and Resume methods is necessary?

    It almost seems to be saying “keep trying until we’re *sure* that the value was set”, but isn’t Interlocked.Exchange pretty much guaranteed to be successful in that respect? What potential problems could occur with just a single (non-looped) Exchange?

  10. @minhvc: Do you have a dual-core CPU and are you performing lots of work in with your Thread class? That’s normal. If you thread is using 100% of that CPU (or core) then it will be using 50% of all CPUs–which will show up as 50% in Task Manager.

  11. Good stuff…wish I’d seen this 6 months ago. Anyway..I have a VB6 app that uses a .NET DLL via COM (my DLL) to insert a bunch of transactions into a SQL database and inteface with another .NET app. The COM DLL opens the connection, handles DB login, inserts transaction records, and handles all the SQL interaction, while the VB app sits and waits. The COM dll currently displays a wait form via another thread to show a animated GIF. Here’s the code that controls the thread:
    _
    Public Sub ShowWaitForm(ByVal Show As Boolean)
    Static thrd As System.Threading.Thread

    If Show Then
    thrd = New System.Threading.Thread(AddressOf ShowForm)
    thrd.Start()
    Else
    If thrd IsNot Nothing Then
    thrd.Abort()
    thrd.Join()
    thrd = Nothing
    End If
    End If
    End Sub
    _
    Private Sub ShowForm()
    Try
    frmWait = New WaitForm
    frmWait.ShowDialog()
    Catch ex As System.Threading.ThreadAbortException
    System.Threading.Thread.ResetAbort()
    Finally
    If frmWait IsNot Nothing Then
    frmWait.Hide()
    frmWait = Nothing
    End If
    ‘Finally
    End Try
    End Sub

    This works for us pretty well, although every now and then, a ThreadAbort Exception is displayed. What are we doing wrong to get this exception? Is there a better way to terminate the thread than ThreadAbort?

  12. I have a problem with needing to suspend a thread that is running a blocking socket operation. Once a receive has started, the operation blocks until it receives something. I need to suspend this block, then allow a send thread to send on the same socket. Once the send finishes or a period of time passes, I need to suspend the send thread that may also be blocking and allow the receive thread to run again. Since I am working with c# and deploying to a device running CE 5.0, I have no timeout on the socket commands (the receivetimeout and sendtimeout are not supported in CE for some crazy reason), no way to notify the socket to stop blocking and if I disconnect the socket that stops the block, the server looses the unique handle of the socket it was conversing with, so server side sends fail regularly when a user trys to ramdomly send information to the connected socket handle that is constantly being disconnected and reconnected. Do you know of a solution for this problem?

  13. Thanks for the article – I was looking for something like this.

    One question though – shouldn’t the SuspendableThread class implement IDisposable since it contains ManualResetEvent members which implement IDisposable (since they ultimately derive from WaitHandle and also explicitly implements IDisposable)?

  14. Sorry, I do not have a detailed answer to this yet, but the bad news is when you try to use the .Suspend after the thread variable name, Visual Studio 2005 with CE 5.0 selected as the deploy option does not include Suspend as a valid option.

    I can only select from these:

    Abort
    IsBackground
    Join
    ManagedThreadId
    Name
    Priority
    Start

    This is a tough one. I was able to tune my code so that I am getting a 3 second response for either a local interactive user or from host/server side requests, however the constant disconnecting and connecting from the socket/server leaves me with a not so persistent socket connection.

    If you know anyone with Compact Frame Work, CE.Net, knowledge, please pass along this situation to them. Thank you, Dave!

  15. Sorry again, I had forgotten about the class you created, suspendableThread. The entire point of this blog…

    After reviewing this again, I think the only problem is if I place my blocking receive or send anywhere the thread is doing work, it will block the suspend request. I will give this a try and also see if it works to change the socket connection to a non-blocking state with a while loop that keeps trying the receive unless a request to send comes up from the client.

    More to come!

  16. Shouldn’t the SuspendableThread class implement IDisposable since it contains ManualResetEvent members which implement IDisposable (since they ultimately derive from WaitHandle and also explicitly implements IDisposable)?

  17. Hi Peter.

    I’m new to threading and have not yet figured out how my threads can suspend themselves without using .Suspend()

    When using your code, how can another class poll MyThread to see if it is suspended?

    Regards
    James

  18. @James, you could simply add a read-only property to check the suspended field:

    public Boolean IsSuspended { get { return suspended; } }

  19. Hi Peter ….

    Nice one!
    Your Implementaion is very good when we’ve multiple threads in our application ….I’ve some different situation but the same work….
    M creating a window service Which take files from a specified folder ,Start a thread,This thread take files one by one, processes the file one by one , then Delete the file.
    In between I want to Pause the window Service.To do this I want to suspend the thread..The problem is Susped is Obsolete.I can not use suspens & Resume……So how I can Implement Suspend & Resume by your Implementation…

    Thanks in advance
    -Gaurav

  20. http://s001.radikal.ru/i194/1001/f2/3b8e742581a0.jpg

    buy cigarettes online new york
    laws about buying cigarettes buy cigarettes in austria mail order cheap cigarettes
    buy advance lights online cigarettes
    buy marlboro cigarette buying cigarettes at age 13 where to buy eve cigarette
    where to buy aeros smokeless cigarettes
    buy gauloises cigarettes buy canada cigarettes e health cigarettes phone order
    where to buy wave cigarettes
    order cigarettes from new york buy chinese cigarettes online marlboro cigarettes buy
    19 to buy cigarettes
    age to buy cigarettes in canada order eclipse cigarettes where to buy cigarettes
    buy reservation cigarettes
    splash cigarettes buy online alternative cigaretts buy american cigarette north carolina order form
    discount mail order cigarettes
    buying cheap cigarettes in the usa order cheyenne cigarettes buy marshall mcgearty cigarettes

  21. Hi,
    I am working on .Net compact frame work 3.5.
    Could you please tell me weather i can use above code in compact framework or not.
    Thanks,
    Babu

Leave a Reply

Your email address will not be published. Required fields are marked *