My DoWork
for backgroundworker1
sets a wait timer via a class WakeUp
, it works well.
The problem right now is that sometimes my while CancellationPending
is ending in an infinite loop. So inside DoWork
there is a call to WaitOne
, the DoWork
sets the wait timer stuff and waits the thread until the timer triggers.
I need for the BackgroundWorker
to shut down right away but as well I have to keep a reference to BackgroundWorker
so I can keep track of each alarm in my program. Why is CancellationPending
taking so long? It never seems to finish. Is there some way to kill off the backgroundworker
without having to wait like this in a while loop for so long?
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 -< <--
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();
}
WakeUp.cs
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);
}
}
}
Possible solution:
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;
but I was trying to avoid this type of code.