steventnorris steventnorris - 2 months ago 21
C# Question

Using WaitHandle.WaitOne

I am attempting to create a windows service that polls every 5 minutes a system and checks for some action that needs done. I have read up on

WaitHandles
and their usefulness in this area, but need to understand how this works.

See code below:

public partial class PollingService : ServiceBase
{
private CancellationTokenSource cancelToken = new CancellationTokenSource();
private Task mainTask = null;
public PollingService()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
mainTask = new Task(pollInterval, cancelToken.Token, TaskCreationOptions.LongRunning);
mainTask.Start();
}
public void pollInterval()
{
CancellationToken cancel = cancelToken.Token;
TimeSpan interval = TimeSpan.FromMinutes(5);
while (!cancel.IsCancellationRequested && !cancel.WaitHandle.WaitOne(interval))
{
if (cancel.IsCancellationRequested)
{
break;
}
EventLog.WriteEntry("*-HEY MAN I'M POLLNG HERE!!-*");
//Polling code goes here. Checks periodically IsCancellationRequested
}
}
protected override void OnStop()
{
cancelToken.Cancel();
mainTask.Wait();
}
}


The above code seems like something that should work from my research, but I don't understand the
!cancel.WaitHandle.WaitOne(interval)
portion. How does this keep the loop going with a wait every five minutes? I need to understand this part of the code to complete my script, or to know if I am completely wrong in my use of the WaitHandle.

This was where I got the idea: Creating a c# windows service to poll a database

Answer

As the article Hans pointed you to explains, the usage here is to have a way to have the thread wait for some specific period of time, but still allow the thread to be woken up prior to the timeout period expiring, e.g. in case you need the thread to terminate early (as here).

That said, this implementation is "old school". :) If you are using .NET 4.5, IMHO the code would work better if you use the async/await idiom (especially since you're already using CancellationTokenSource):

    protected async override void OnStart(string[] args)
    {   
        try
        {
            await pollInterval();
        }
        catch (TaskCanceledException) { }
    }

    public async Task pollInterval()
    {
        CancellationToken cancel = cancelToken.Token;
        TimeSpan interval = TimeSpan.FromMinutes(5);
        while (true)
        {
            await Task.Delay(interval, cancel);
            EventLog.WriteEntry("*-HEY MAN I\"M POLLNG HERE!!-*");
            //Polling code goes here. Checks periodically IsCancellationRequested
        }
    }

With the above, the code more correctly expresses the intent. That is, whereas the WaitHandle version appears primarily to be waiting to be signaled to exit, even though the primary mechanism at work is actually the timeout for the wait, here the code clearly indicates that the primary intent is to delay, with the possibility of the delay being cancelled.