我正在构建一个多线程的Windows服务。一旦所有线程都通过,我有点困难找出干净地停止服务的最佳方法。代码如下。我查看了ManualResetEvent,CountdownEvent并使用了Interlocked。我不确定哪一个最适合我的实施。
感谢您的帮助。
private bool _isExiting;
private bool IsExiting //if this is set to true exit but wait for all threads
{
get { return _isExiting; }
set
{
_isExiting = value;
if (value)
Stop();
}
}
private JobProfiler profiler;
protected override void OnStart(string[] args)
{
try
{
profiler = new Profiler(MaxThreads);
ThreadPool.QueueUserWorkItem(DoWork); // main thread set up thread for work
}
catch (Exception ex)
{
LogError(ex);
Stop();
}
}
protected void DoWork(object data)
{
while (!IsExiting)
{
try
{
profiler.RunProfiles(profiles); //this should wait until all child threads are done
Thread.Sleep(ThreadSleep); //sleep before next iteration
}
catch (Exception ex)
{
LogError(ex);
errorCount++;
if (errorCount > 10) //if 10 serious errors happen stop the service
{
IsExiting = true;
break;
}
}
}
}
protected override void OnStop()
{
try
{
if(profiler != null)
profiler.IsExiting = true; //setting a variable here to signal all remaining threads to stop
//here it should be waiting for the main and child threads to finish
base.OnStop();
}
catch
{
base.OnStop();
}
}
//profiler class
//******************************************************
private readonly Semaphore _throttle; //setting up a throttle for the number of threads we will allow to execute at once
public void RunProfiles(List<Profiles> profiles)
{
foreach (var profile in profiles)
{
if (IsExiting) break; //if an exit command is called stop iterating
_throttle.WaitOne(); // Wait on a semaphore slot to become available
ThreadPool.QueueUserWorkItem(RunProfile, profile ); //then add to thread queue
}
}
private void RunProfile(object profile)
{
try
{
var p = (profile as Profile);
if (p == null || IsExiting)
{
_throttle.Release(); // Release the semaphore slot if profile not found or if we're exiting
return;
}
//****
//do a bunch of stuff
//****
_throttle.Release(); // Release the semaphore slot
}
catch (Exception ex)
{
log.Error(ex);
_throttle.Release(); // Release the semaphore slot
}
}
答案 0 :(得分:0)
我会使用Tasks(来自.NET 4.0的TPL)并使用CancellationToken取消任务,如果发生Stop事件或某些异常并且您想要停止服务。
但是如果你想坚持使用信号量或较旧的同步原语,你的解决方案就可以正常工作。
另见本文:Threading
有几个有用的例子可以帮助您选择最佳解决方案。我相信CountdownEvent是高度优化的并且与操作系统无关,所以从你的列表中我会选择那个。