16

How can I pause/resume a thread? Once I Join() a thread, I can't restart it. So how can I start a thread and make it pause whenever the button 'pause' is pressed, and resume it when resume button is pressed?

The only thing this thread does, is show some random text in a label control.

Yustme
  • 6,125
  • 22
  • 75
  • 104
  • 1
    Can you add your code in your question – Adil May 06 '12 at 10:15
  • There is no code at the moment. I'm still thinking how to implement this project I have in my head. All I can tell you that I know from experience with my work with threading, once a thread is joined with the main thread, there is no way I can resume/restart it. – Yustme May 06 '12 at 10:32

4 Answers4

25

Maybe the ManualResetEvent is a good choice. A short example:

private static EventWaitHandle waitHandle = new ManualResetEvent(initialState: true); 

// Main thread
public void OnPauseClick(...) {
   waitHandle.Reset();
}

public void OnResumeClick(...) {
   waitHandle.Set();
}

// Worker thread
public void DoSth() {
   while (true) {
     // show some random text in a label control (btw. you have to
     // dispatch the action onto the main thread)
     waitHandle.WaitOne(); // waits for the signal to be set
   }
}
Johannes Egger
  • 3,874
  • 27
  • 36
  • while(true) // This is not a good ides, There must be a way to Sleep the thread and then awake the thread from sleep when needed so that it won't consume processing power. – Hammad Sajid Sep 15 '22 at 19:27
7

I could suggest you to read Threading in C#, by Joe Albahari, particularly Suspend and Resume section:

A thread can be explicitly suspended and resumed via the deprecated methods Thread.Suspend and Thread.Resume. This mechanism is completely separate to that of blocking. Both systems are independent and operate in parallel.

A thread can suspend itself or another thread. Calling Suspend results in the thread briefly entering the SuspendRequested state, then upon reaching a point safe for garbage collection, it enters the Suspended state. From there, it can be resumed only via another thread that calls its Resume method. Resume will work only on a suspended thread, not a blocked thread.

From .NET 2.0, Suspend and Resume have been deprecated, their use discouraged because of the danger inherent in arbitrarily suspending another thread. If a thread holding a lock on a critical resource is suspended, the whole application (or computer) can deadlock. This is far more dangerous than calling Abort — which results in any such locks being released (at least theoretically) by virtue of code in finally blocks.

SuspendRequested state

Community
  • 1
  • 1
gliderkite
  • 8,828
  • 6
  • 44
  • 80
  • Your block quote makes a distinction between a suspended thread versus a blocked thread, but the diagram does not seem to make this distinction. Is this intentional? – Tung May 06 '12 at 10:31
  • @Tung A thread is deemed blocked when its execution is paused for some reason, such as when Sleeping or waiting for another to end via Join or EndInvoke. In code: `bool blocked = (someThread.ThreadState & ThreadState.WaitSleepJoin) != 0;`. So why there's no distinction in the diagram. See [this](http://www.albahari.com/threading/part2.aspx#_Blocking). – gliderkite May 06 '12 at 10:36
  • @gliderkite, I know, so that's why I was asking how to do this and that's why there is no code at the moment to show, simply because I haven't started yet. Just to remind you, in your first line of your first answer, you where pointing to 'no code available' and I was explaining why. – Yustme May 06 '12 at 10:40
  • @Yustme I see, just a misunderstanding. – gliderkite May 06 '12 at 10:42
  • @Tung probably ("A thread is not deemed blocked if its execution is paused via the (**deprecated**) Suspend method"). – gliderkite May 06 '12 at 10:48
1

It's not the best idea to manually suspend and resume threads. However, you can easily simulate this behavior by using thread synchronization primitives (like ManualResetEvent)

Take a look at this question, you may find it helpful.

But I believe you can easily achieve your goal of 'showing random text in a label control' on a time basis by using timers.

Here is a quick example using DispatcherTimer

var timer = new DispatcherTimer(); 
timer.Tick += (s, e) => Label.Text = GetRandomText(); 
timer.Interval = TimeSpan.FromMilliseconds(500); 
timer.Start();

You can pause it by calling timer.Stop() and then timer.Start() again to resume.

Community
  • 1
  • 1
Andrew Khmylov
  • 732
  • 5
  • 18
  • Hi, this looks nice, can I put this code in a separate thread as well? Because I don't want to block the GUI thread. – Yustme May 06 '12 at 10:34
  • @Yustme: AFAIK the code of `DispatcherTimer` executes on the GUI thread. If you want a separate thread use `System.Threading.Timer`. – Tudor May 06 '12 at 12:19
  • Tudor is right, so if you got some 'heavy' code that needs to be executed on timer's ticks, use separate thread. But if you just need to update the text block, using `DispatcherTimer` is fine and won't block your UI. – Andrew Khmylov May 07 '12 at 11:04
1

Here's two ways that's worked for me. Both assume that the worker thread has it's own processing loop.

  1. Have the thread invoke a callback to request permission to keep going
  2. Have the parent invoke a method on the thread's class to signal it

The console application example below shows both approaches, using a callback to pause/continue, and a worker method to stop. Another advantage of the callback method is that it's also convenient for passing back status updates while it's checking for permission to continue.

using System;
using System.Threading;

namespace ConsoleApplication7
{
    class Program
    {
        static bool keepGoing;
        static void Main(string[] args)
        {
            keepGoing = true;
            Worker worker = new Worker(new KeepGoingDelegate(KeepGoing));
            Thread thread = new Thread(worker.DoWork);
            thread.IsBackground = true;
            thread.Start();

            while (thread.ThreadState != ThreadState.Stopped)
            {
                switch (Console.ReadKey(true).KeyChar)
                {
                    case 'p':
                        keepGoing = false;
                        break;
                    case 'w':
                        keepGoing = true;
                        break;
                    case 's':
                        worker.Stop();
                        break;
                }
                Thread.Sleep(100);
            }
            Console.WriteLine("Done");
            Console.ReadKey();
        }

        static bool KeepGoing()
        {
            return keepGoing;
        }
    }

    public delegate bool KeepGoingDelegate();
    public class Worker
    {
        bool stop = false;
        KeepGoingDelegate KeepGoingCallback;
        public Worker(KeepGoingDelegate callbackArg)
        {
            KeepGoingCallback = callbackArg;
        }

        public void DoWork()
        {
            while (!stop)
            {
                Console.Write(KeepGoingCallback()?"\rWorking":"\rPaused ");

                Thread.Sleep(100);
            }
            Console.WriteLine("\nStopped");
        }

        public void Stop()
        {
            stop = true;
        }
    }
}
Ed Power
  • 8,310
  • 3
  • 36
  • 42
  • Hi, for the life of me I am having trouble understanding delegates. I can figure out how to stop the thread, but I do not understand how you are restarting it? – Zev Feb 29 '16 at 17:35
  • @Zev - a delegate isjust placeholder for a method, so that you can pass it into an instance of another class so that it can execute it. In my example the parent passes the `KeepGoing()` method into the worker, which it periodically calls to check back with the parent to see if it should keep going. The worker thread doesn't restart each time - it's launched once and keeps going until it gets a stop signal. – Ed Power Feb 29 '16 at 19:54