title: Threading - How to terminate a work/background thread with UI interaction
body: <p>Compact Framework, Windows Mobile 6, C#.</p>
  
  <p>I'm having a go at some background threading on the compact framework, and have a question re: terminating the worker thread.</p>
  
  <p><strong>The Code</strong></p>
  
  <p>I have the following ThreadWorker class (code from <a href="http://www.yoda.arachsys.com/csharp/threads/shutdown.shtml" rel="nofollow">here</a>), which when executed, will perform a check at certain points to see if it should quit or not.....</p>
  
  <pre><code>public class ThreadWorker 
  {
  
      public event EventHandler&lt;ProgressEventArgs&gt; OnProgress;
  
      protected virtual void Progress(ProgressEventArgs args)
      {
          if (OnProgress != null)
              OnProgress(this, args);
      }
  
      private void DoLongProcess()
      {
          // This will take a long time.
          Thread.Sleep(15000);
          Progress(new ProgressEventArgs("Some info for the UI to display."));
          Thread.Sleep(15000);
      }
  
      public void DoSomeBackgroundWork()
      {
          try
          {
              while (!Stopping)
              {
                  DoLongProcess();
                  if (Stopping) return;
  
                  DoLongProcess();
                  if (Stopping) return;
  
                  DoLongProcess();
                  if (Stopping) return;
  
                  DoLongProcess();
                  if (Stopping) return;
              }
          }
          finally
          {
              SetStopped();
          }
  
          Console.WriteLine("DoSomeBackgroundWork: Terminating gracefully.");
      }
  
      /// &lt;summary&gt;
      /// Lock covering stopping and stopped
      /// &lt;/summary&gt;
      readonly object locker = new object();
  
      /// &lt;summary&gt;
      /// Whether or not the worker thread has been asked to stop
      /// &lt;/summary&gt;
      bool stopping = false;
  
      /// &lt;summary&gt;
      /// Whether or not the worker thread has stopped
      /// &lt;/summary&gt;
      bool stopped = false;
  
      /// &lt;summary&gt;
      /// Returns whether the worker thread has been asked to stop.
      /// This continues to return true even after the thread has stopped.
      /// &lt;/summary&gt;
      public bool Stopping
      {
          get
          {
              lock (locker)
              {
                  return stopping;
              }
          }
      }
  
      /// &lt;summary&gt;
      /// Returns whether the worker thread has stopped.
      /// &lt;/summary&gt;
      public bool Stopped
      {
          get
          {
              lock (locker)
              {
                  return stopped;
              }
          }
      }
  
      /// &lt;summary&gt;
      /// Tells the worker thread to stop, typically after completing its 
      /// current work item. (The thread is *not* guaranteed to have stopped
      /// by the time this method returns.)
      /// &lt;/summary&gt;
      public void Stop()
      {
          lock (locker)
          {
              stopping = true;
          }
      }
  
      /// &lt;summary&gt;
      /// Called by the worker thread to indicate when it has stopped.
      /// &lt;/summary&gt;
      void SetStopped()
      {
          lock (locker)
          {
              stopped = true;
          }
      }
  }
  </code></pre>
  
  <p>...and the following form initiates the thread...</p>
  
  <pre><code>public partial class Test : Form
  {
      public Test()
      {
          InitializeComponent();
      }
  
      private ThreadWorker myThreadWorker;
      private Thread t = null;
  
      private void Test_Load(object sender, EventArgs e)
      {
          myThreadWorker = new ThreadWorker();
  
          myThreadWorker.OnProgress += new EventHandler&lt;ProgressEventArgs&gt;(myThreadWorker_OnProgress);
      }
  
      private void miStart_Click(object sender, EventArgs e)
      {
          try
          {
              listResults.Items.Insert(0, "Set-up Thread.");
              t = new Thread(myThreadWorker.DoSomeBackgroundWork);
              t.Name = "My Thread";
              t.Priority = ThreadPriority.BelowNormal;
              t.Start();
  
              listResults.Items.Insert(0, "Thread started.");
  
          }
          catch (Exception ex)
          {
              MessageBox.Show(ex.Message);
          }
      }
  
      private void miStop_Click(object sender, EventArgs e)
      {
          try
          {
              listResults.Items.Insert(0, "Waiting for My Thread to terminate.");
              listResults.Refresh();
              myThreadWorker.Stop();
              t.Join();
              listResults.Items.Insert(0, "My Thread Finished.");
          }
          catch (Exception ex)
          {
              MessageBox.Show(ex.Message);
          }
      }
  
      private delegate void InsertToListBoxDelegate(String text);
      private void InsertToListBox(String text)
      {
          if (InvokeRequired)
              Invoke(new InsertToListBoxDelegate(InsertToListBox), new object[] { text });
          else
          {
              listResults.Items.Insert(0, "{0}".With(text));
              listResults.Refresh();
          }
      }
  
      void myThreadWorker_OnProgress(object sender, ProgressEventArgs e)
      {
          InsertToListBox(e.Text);
      }
  }
  </code></pre>
  
  <p><strong>The Problem</strong></p>
  
  <p>When I click on the Stop button it calls...</p>
  
  <pre><code>myThreadWorker.Stop();
  t.Join();
  listResults.Items.Insert(0, "My Thread Finished.");
  </code></pre>
  
  <p>...what I was expecting is for the ThreadWorker to carry on with its current DoLongProcess() until it had finished, and still raise event to the UI via the OnProgress event handler and myThreadWorker_OnProgress.     </p>
  
  <p>However, what actually happens is when OnProgress is raised, the application freezes on the line reading...</p>
  
  <pre><code> Invoke(new InsertToListBoxDelegate(InsertToListBox), new object[] { text });
  </code></pre>
  
  <p><strong>The question</strong></p>
  
  <p>How do I call... </p>
  
  <pre><code>myThreadWorker.Stop();
  t.Join();
  </code></pre>
  
  <p>...and still respond to events from the background thread until it is terminated?</p>