title: Cancelling a BackgroundWorker
body: <p>My <code>DoWork</code> for <code>backgroundworker1</code> sets a wait timer via a class <code>WakeUp</code>, it works well.</p>
  
  <p>The problem right now is that sometimes my <code>while CancellationPending</code> is ending in an infinite loop. So inside <code>DoWork</code> there is a call to <code>WaitOne</code>, the <code>DoWork</code> sets the wait timer stuff and waits the thread until the timer triggers.</p>
  
  <p>I need for the <code>BackgroundWorker</code> to shut down right away but as well I have to keep a reference to <code>BackgroundWorker</code> so I can keep track of each alarm in my program. Why is <code>CancellationPending</code> taking so long? It never seems to finish. Is there some way to kill off the <code>backgroundworker</code> without having to wait like this in a while loop for so long?</p>
  
  <pre><code>switch (alarmNum)
  {
      case 1:
                  WakeUp.CancelWakeUp(threadHandles[removal]);
          if(backgroundworker1.IsBusy)
          {
  
              backgroundworker1.CancelAsync();
          }
  
          while(backgroundworker1.CancellationPending)
          {
  
          }
  
          backgroundworker1.RunWorkerAsync();
          break;
      case 2:
          if (backgroundworker2.IsBusy)
          {
              backgroundworker2.CancelAsync();
          }
          backgroundworker2.RunWorkerAsync();
          break;
      case 3:
          if (backgroundworker3.IsBusy)
          {
              backgroundworker3.CancelAsync();
          }
          backgroundworker3.RunWorkerAsync();
          break;
      case 4:
          if (backgroundworker4.IsBusy)
          {
              backgroundworker4.CancelAsync();
          }
          backgroundworker4.RunWorkerAsync();
          break;
      case 5:
          if (backgroundworker5.IsBusy)
          {
              backgroundworker5.CancelAsync();
          }
          backgroundworker5.RunWorkerAsync();
          break;
  }
  
  
  
      private void bw1_DoWork(object sender, DoWorkEventArgs e)
      {
          BackgroundWorker worker = sender as BackgroundWorker;
  
  
          if (worker.CancellationPending == true)
          {
            e.Cancel = true;
          }
  
          WakeUp temp = new WakeUp("spalarm1");
          threadHandles[0] = temp.tHandle;
          temp.initWakeUp(dtCurSpan);
  
          //****************************
                It's blocking here -&lt; &lt;--
                temp.DoWork sets a system timer so its blocking
                with a call to WaitOne inside WakeUp. The timer I'm setting
                is called a waitable timer so its blocking since the system is
                waiting for it to expire so the thread can end
             *******************************/
          temp.DoWork();
      }
  </code></pre>
  
  <p>WakeUp.cs</p>
  
  <pre><code>using System;
  using System.Collections.Generic;
  using System.Linq;
  using System.Text;
  
  using System.Windows.Controls;
  using System.Threading.Tasks;
  using System.Threading;
  using System.Runtime.InteropServices;
  using Microsoft.Win32.SafeHandles;
  using System.ComponentModel;
  using System.Diagnostics;
  
  namespace WpfApplication1
  {
      class WakeUp
      {
          public delegate void TimerCompleteDelegate(IntPtr complretionArg,
                                                 UInt32 timerLow, UInt32 timerHigh);
  
          public SafeWaitHandle tHandle;
          bool rslt;
  
          //Various imports of kernel32.dll so the waitable timer can be set
          //on the system
          [DllImport("kernel32.dll")]
          public static extern SafeWaitHandle CreateWaitableTimer(IntPtr lpTimerAttributes, bool bManualReset, string lpTimerName);
  
          [DllImport("kernel32.dll", SetLastError = true)]
          [return: MarshalAs(UnmanagedType.Bool)]
          public static extern bool SetWaitableTimer(SafeWaitHandle hTimer, [In] ref long pDueTime, int lPeriod, IntPtr pfnCompletionRoutine, IntPtr lpArgToCompletionRoutine, bool fResume);
  
          [DllImport("kernel32.dll", SetLastError = true)]
          public static extern bool CancelWaitableTimer(SafeWaitHandle hTimer);
  
          //SafeHandle.DangerousGetHandle Method
          [DllImport("kernel32.dll", SetLastError = true)]
          [return: MarshalAs(UnmanagedType.Bool)]
          public static extern bool CloseHandle(IntPtr hObject);
  
          //The constructor will use a TimeSpan to set a waitable timer
          public WakeUp(string wtName)
          {
              tHandle = CreateWaitableTimer(IntPtr.Zero, true, wtName);
          }
  
          public int initWakeUp(TimeSpan smParam)
          {
              //The number of ticks needs to be negated to set a waitable timer in this fashion
              long waketicks = -smParam.Ticks;
              rslt = SetWaitableTimer(tHandle, ref waketicks, 0, IntPtr.Zero, IntPtr.Zero, true);
  
              if(!rslt)
              {
                  return Marshal.GetLastWin32Error();
              }
              else
              {
                  return 0;
              }
          }
  
          private static Exception GetWin32Exception()
          {
              return Marshal.GetExceptionForHR(Marshal.GetHRForLastWin32Error());
          }
  
          public int DoWork()
          {
              using (EventWaitHandle wh = new EventWaitHandle(false, EventResetMode.AutoReset))
              {
                  wh.SafeWaitHandle = tHandle;
                  wh.WaitOne();
                  Thread.Sleep(5000);
              }
  
              return 0;
          }
  
  
  
          //This function needs to check the return value of
          //CancelWaitableTimer
          static public void CancelWakeUp(SafeWaitHandle clHandle)
          {
              CancelWaitableTimer(clHandle);
          }
      }
  }
  </code></pre>
  
  <p>Possible solution:</p>
  
  <pre><code>case 1:
  WakeUp.CancelWakeUp(threadHandles[removal]);
  
  threadHandles[removal] = null;
  backgroundworker1.CancelAsync();
  backgroundworker1.Dispose();
  
  backgroundworker1 = new BackgroundWorker();
  backgroundworker1.WorkerReportsProgress = true;
  backgroundworker1.WorkerSupportsCancellation = true;
  backgroundworker1.DoWork += new DoWorkEventHandler(bw1_DoWork);
  backgroundworker1.ProgressChanged += new ProgressChangedEventHandler(bw1_ProgressChanged);
  backgroundworker1.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw1_RunWorkerCompleted);
  
  backgroundworker1.RunWorkerAsync();
  break;
  </code></pre>
  
  <p>but I was trying to avoid this type of code.</p>