Why you should never suspend a thread


It's almost as bad as terminating a thread.

Instead of just answering a question, I'm going to ask you the questions and see if you can come up with the answers.

Consider the following program, in (gasp) C#:

using System.Threading;
using SC = System.Console;

class Program {
  public static void Main() {
    Thread t = new Thread(new ThreadStart(Program.worker));
    t.Start();
    SC.WriteLine("Press Enter to suspend");
    SC.ReadLine();
    t.Suspend();
    SC.WriteLine("Press Enter to resume");
    SC.ReadLine();
    t.Resume();
  }
  static void worker() {
    for (;;) SC.Write("{0}\r", System.DateTime.Now);
  }
}

When you run this program and hit Enter to suspend, the program hangs. But if you change the worker function to just "for(;;) {}" the program runs fine. Let's see if we can figure out why.

The worker thread spends nearly all its time calling System.Console.WriteLine, so when you call Thread.Suspend(), the worker thread is almost certainly inside the System.Console.WriteLine code.

Q: Is the System.Console.WriteLine method threadsafe?

Okay, I'll answer this one: Yes. I didn't even have to look at any documentation to figure this out. This program calls it from two different threads without any synchronization, so it had better be threadsafe or we would be in a lot of trouble already even before we get around to suspending the thread.

Q: How does one typically make an object threadsafe?

Q: What is the result of suspending a thread in the middle of a threadsafe operation?

Q: What happens if - subsequently - you try to access that same object (in this case, the console) from another thread?

These results are not specific to C#. The same logic applies to Win32 or any other threading model. In Win32, the process heap is a threadsafe object, and since it's hard to do very much in Win32 at all without accessing the heap, suspending a thread in Win32 has a very high chance of deadlocking your process.

So why is there even a SuspendThread function in the first place?

Debuggers use it to freeze all the threads in a process while you are debugging it. Debuggers can also use it to freeze all but one thread in a process, so you can focus on just one thread at a time. This doesn't create deadlocks in the debugger since the debugger is a separate process.

Comments (8)
  1. Jack Mathews says:

    Q: How does one typically make an object threadsafe?

    A. Working off of the stack rather than the heap, thread local storage, and critical sections. (I know you’re looking for critical sections :) )

    Q: What is the result of suspending a thread in the middle of a threadsafe operation?

    Critical section never gets unlocked if you’re inside it.

    Q: What happens if – subsequently – you try to access that same object (in this case, the console) from another thread?

    Deadlock…

    One thing, btw, that suspendthread is good for, and perfectly safe, is for a thread to suspend itself. That’s been a useful tool to me in the past, and probably the only OTHER useful purpose of it.

  2. bryan says:

    since you’re on processes here (this is 99% off-topic) if you have a process that passes an uri to the system’s protocol handler (this is an asynchronous pluggable protocol that’s being passed, a self-rolled one, but it could be http:, outlook: , etc.) can one find out what process the uri was passed from by knowing what the uri is?

  3. Raymond Chen says:

    Sorry, I don’t understand the question. Who is "one"? The process that is responsible for handling the protocol? If you choose DDE as your protocol invocation mechanism, I believe DDE lets you determine who is on the other end of a DDE conversation.

  4. Ben Wilhelm says:

    I had a bug on this exact matter – I was suspending a thread, and it was ending up in the middle of a memory allocation mutex. Grrr. Useless function – totally useless.

    I’ve always been trying to think of a way to do SuspendThread() without having to make the thread poll constantly, but have never managed to come up with one.

  5. Jack Mathews says:

    1) Not useless. Again, if used by the thread itself, it’s extremely useful.
    2) Well, there’s always going to HAVE to be some way to poll. A way would be to put the unsafe code in critical sections, and make the thread that suspends your thread is also enter the critical section. Then you can guarantee that only when you’re out of it can the suspend get called. But in this case, you may as well just poll in a safe place, rather than this.

  6. bryan says:

    ‘Who is "one"? The process that is responsible for handling the protocol? If you choose DDE as your protocol invocation mechanism, I believe DDE lets you determine who is on the other end of a DDE conversation.’

    The one was grammatical, as in any unnamed individual, or I guess process as well in this case.

    The problem I’m thinking about specifically is that I’ve rolled my own pluggable protocol in a third-party scripting language, and registered it as such via the registry, this language however has no understanding of DDE, and no especially easy way of implementing it, I can however pass off the protocol information via the command line and using Standard I/O get information back, so what I’m wondering (and I figure it’s probably not doable) is there anyway for a third process to work out from just the protocol information, what process invoked the uri.

    Sorry for taking up the time on your blog with this, but I figure there are not very many people out there competent to answer this question with either an authoritative no, or a ‘read these 15 links’ yes.

  7. Breaking The Secrets —– Dessecting The Stack Part3 Walking The Callstack Last time I cover much…

Comments are closed.

Skip to main content