'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]

Published Fri, Oct 13 2006 15:25 by PeterRitchie

Comments

# 'System.Threading.Thread.Suspend()' is obsolete: 'Thread.Suspend has b

You've been kicked (a good thing) - Trackback from DotNetKicks.com

Thursday, November 09, 2006 3:49 PM by DotNetKicks.com

# re: 'System.Threading.Thread.Suspend()' is obsolete: 'Thread.Suspend has been deprecated...

Pure Waste..........

Wednesday, November 22, 2006 5:23 AM by Pooja

# re: Pure Waste

Interesting, care to elaborate?

Wednesday, November 22, 2006 7:00 AM by PeterRitchie

# Help with web design

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.

Sunday, January 07, 2007 4:38 PM by hillbilly

# re: online store

"make an online store" is really general and doesn't give us much to focus a response on.

If you're looking for an ASP.NET solution you can have a look at the ASP.NET starter kits, two of which is an fully-working e-commerce sites: http://www.asp.net/downloads/starterkits/TheBeerHouse.aspx?tabid=62 and http://www.asp.net/downloads/starterkits/PaypalEcommerce.aspx?tabid=62

Thursday, January 11, 2007 9:51 AM by PeterRitchie

# Who can help me with .httpaccess ?

Who can help me with .httpaccess ?

where i can fined full information about .httpaccess file syntaxis?

Sunday, February 04, 2007 2:55 PM by JackyMool

# test page

.NET Tips &amp; Tricks Michael Nemtsev, Microsoft MVP Last update: June 13 , 2007 Document version 0

Wednesday, June 13, 2007 2:00 PM by Michael's Coding Den

# .NET Tips: Threads

INFO: · One of the registers stored in the TLS is a program counter that tells the thread which instruction

Thursday, June 14, 2007 9:43 AM by Michael's Coding Den

# re: 'System.Threading.Thread.Suspend()' is obsolete: 'Thread.Suspend has been deprecated...

Good Effort Peter.

I learnt a lot from your post.

Thanks a lot.

Thursday, October 11, 2007 8:24 AM by Ajit

# re: 'System.Threading.Thread.Suspend()' is obsolete: 'Thread.Suspend has been deprecated...

What do you think about BackgroundWorker class? Can it be used for this scenario?

Monday, November 26, 2007 5:16 AM by Arun

# re: 'System.Threading.Thread.Suspend()' is obsolete: 'Thread.Suspend has been deprecated...

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.

Monday, November 26, 2007 2:52 PM by PeterRitchie

# re: 'System.Threading.Thread.Suspend()' is obsolete: 'Thread.Suspend has been deprecated...

Brilliant! Exactly what I was looking for.

Thanks man! Appreciate it.

Thursday, January 31, 2008 10:00 AM by Joy

# re: 'System.Threading.Thread.Suspend()' is obsolete: 'Thread.Suspend has been deprecated...

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?

Tuesday, March 11, 2008 11:01 AM by Bob Bryan

# re: 'System.Threading.Thread.Suspend()' is obsolete: 'Thread.Suspend has been deprecated...

I would suggest creating a new class deriving from SuspendableThread, then aggregating that new class.

Tuesday, March 11, 2008 11:09 AM by PeterRitchie

# re: 'System.Threading.Thread.Suspend()' is obsolete: 'Thread.Suspend has been deprecated...

good work !!!!!

Friday, March 14, 2008 5:55 PM by Deependu

# re: 'System.Threading.Thread.Suspend()' is obsolete: 'Thread.Suspend has been deprecated...

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.

Wednesday, July 02, 2008 12:48 AM by Vikram

# re: 'System.Threading.Thread.Suspend()' is obsolete: 'Thread.Suspend has been deprecated...

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.

Wednesday, July 02, 2008 10:56 AM by PeterRitchie

# re: 'System.Threading.Thread.Suspend()' is obsolete: 'Thread.Suspend has been deprecated...

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.

Thursday, July 03, 2008 3:33 AM by Vikram

# re: 'System.Threading.Thread.Suspend()' is obsolete: 'Thread.Suspend has been deprecated...

@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.

Thursday, July 03, 2008 10:32 AM by PeterRitchie

# re: 'System.Threading.Thread.Suspend()' is obsolete: 'Thread.Suspend has been deprecated...

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?

Wednesday, September 10, 2008 12:47 PM by Ali Zamurad

# re: 'System.Threading.Thread.Suspend()' is obsolete: 'Thread.Suspend has been deprecated...

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?

Tuesday, October 28, 2008 11:21 AM by Aaron

# CPU resouse

When use the thread class for my application. It use 50% CPU resource. How to fix it?

Friday, October 31, 2008 2:31 AM by minhvc

# re: 'System.Threading.Thread.Suspend()' is obsolete: 'Thread.Suspend has been deprecated...

@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.

Friday, October 31, 2008 8:43 AM by PeterRitchie

# re: 'System.Threading.Thread.Suspend()' is obsolete: 'Thread.Suspend has been deprecated...

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:

<System.Runtime.InteropServices.ComVisible(False)> _

   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

   <System.Runtime.InteropServices.ComVisible(False)> _

   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?  

Thursday, January 15, 2009 3:05 PM by Steve

# re: 'System.Threading.Thread.Suspend()' is obsolete: 'Thread.Suspend has been deprecated...

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?

Monday, January 26, 2009 11:10 PM by John M.

# re: 'System.Threading.Thread.Suspend()' is obsolete: 'Thread.Suspend has been deprecated...

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)?

Wednesday, January 28, 2009 2:03 PM by Dave Black

# re: 'System.Threading.Thread.Suspend()' is obsolete: 'Thread.Suspend has been deprecated...

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!

Wednesday, January 28, 2009 3:25 PM by John M.

# re: 'System.Threading.Thread.Suspend()' is obsolete: 'Thread.Suspend has been deprecated...

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!

Wednesday, January 28, 2009 3:40 PM by John M.

# re: 'System.Threading.Thread.Suspend()' is obsolete: 'Thread.Suspend has been deprecated...

This worked! I used Async Sockets so they are non-Blocking and I was able to build the solution successful.

Sunday, February 01, 2009 3:57 PM by John M.

# re: 'System.Threading.Thread.Suspend()' is obsolete: 'Thread.Suspend has been deprecated...

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)?

Sunday, February 01, 2009 11:01 PM by Dave Black

# re: 'System.Threading.Thread.Suspend()' is obsolete: 'Thread.Suspend has been deprecated...

@Dave, yes, it would be better if SuspendableThread implemented IDisposable.

Monday, February 02, 2009 8:08 AM by PeterRitchie

# I'm curious...

Anyone know how old this forum is? As in what year it was started?

Saturday, April 04, 2009 8:52 AM by Bapproroumn

# re: 'System.Threading.Thread.Suspend()' is obsolete: 'Thread.Suspend has been deprecated...

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

Friday, April 10, 2009 1:49 AM by James Hall

# re: 'System.Threading.Thread.Suspend()' is obsolete: 'Thread.Suspend has been deprecated...

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

public Boolean IsSuspended { get { return suspended; } }

Friday, April 10, 2009 7:59 AM by PeterRitchie

# re: 'System.Threading.Thread.Suspend()' is obsolete: 'Thread.Suspend has been deprecated...

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

Thursday, July 09, 2009 6:54 AM by Gaurav

Leave a Comment

(required) 
(required) 
(optional)
(required)