Reputation: 33
I need to perform few tasks inside a Windows Service I am writing in parallel. I am using VS2013, .NET 4.5 and this thread Basic design pattern for using TPL inside windows service for C# shows that TPL is the way to go.
Below is my implementation. I was wondering if anyone can tell me if I have done it correctly!
public partial class FtpLink : ServiceBase
{
private readonly CancellationTokenSource _cancellationTokenSource = new CancellationTokenSource();
private readonly ManualResetEvent _runCompleteEvent = new ManualResetEvent(false);
public FtpLink()
{
InitializeComponent();
// Load configuration
WebEnvironment.Instance.Initialise();
}
protected override void OnStart(string[] args)
{
Trace.TraceInformation("DatabaseToFtp is running");
try
{
RunAsync(_cancellationTokenSource.Token).Wait();
}
finally
{
_runCompleteEvent.Set();
}
}
protected override void OnStop()
{
Trace.TraceInformation("DatabaseToFtp is stopping");
_cancellationTokenSource.Cancel();
_runCompleteEvent.WaitOne();
Trace.TraceInformation("DatabaseToFtp has stopped");
}
private async Task RunAsync(CancellationToken cancellationToken)
{
while (!cancellationToken.IsCancellationRequested)
{
Trace.TraceInformation("Working");
// Do the actual work
var tasks = new List<Task>
{
Task.Factory.StartNew(() => new Processor().ProcessMessageFiles(), cancellationToken),
Task.Factory.StartNew(() => new Processor().ProcessFirmware(), cancellationToken)
};
Task.WaitAll(tasks.ToArray(), cancellationToken);
// Delay the loop for a certain time
await Task.Delay(WebEnvironment.Instance.DatabasePollInterval, cancellationToken);
}
}
}
Upvotes: 2
Views: 1463
Reputation: 149558
There are a few things i would do differently:
OnStart
should execute in a timely fashion. Common practice is to defer work to a background thread which is in charge of doing the actual work. You're actually doing that but blocking that thread with a call to Task.Wait
, which kind of makes the offloading to a background thread useless, because execution becomes synchronous again.ManualResetEvent
the other way around. You're wrapping your RunAsync
method in a try-finally
block, but you're only calling WaitOne
from OnStop
. I'm not really sure you need a lock here at all, it doesn't seem (from your current code) that this code is being invoked in parallel. Instead, you can store the Task
returned by RunAsync
in a field and wait on it to complete.WaitAll
. Instead, you could use the asynchronous version, Task.WhenAll
, which can be asynchronously waited.Upvotes: 2