C# 处理windows服务错误的正确方法
我正在构建一个多线程windows服务。一旦所有线程都运行完毕,我就很难找到干净地停止服务的最佳方法。代码如下。我已经看过ManualResetEvent、CountdownEvent和使用Interlocked。我不确定哪一个最适合我的实现 谢谢你的帮助C# 处理windows服务错误的正确方法,c#,multithreading,windows-services,threadpool,semaphore,C#,Multithreading,Windows Services,Threadpool,Semaphore,我正在构建一个多线程windows服务。一旦所有线程都运行完毕,我就很难找到干净地停止服务的最佳方法。代码如下。我已经看过ManualResetEvent、CountdownEvent和使用Interlocked。我不确定哪一个最适合我的实现 谢谢你的帮助 private bool _isExiting; private bool IsExiting //if this is set to true exit but wait for all threads {
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
}
}
private bool正在退出;
private bool isexit//如果设置为true,则退出,但等待所有线程
{
获取{return\u isExiting;}
设置
{
_isExiting=值;
如果(值)
停止();
}
}
私人作业档案器;
启动时受保护的覆盖无效(字符串[]args)
{
尝试
{
探查器=新的探查器(MaxThreads);
ThreadPool.QueueUserWorkItem(DoWork);//主线程为工作设置线程
}
捕获(例外情况除外)
{
对数误差(ex);
停止();
}
}
受保护的空工作(对象数据)
{
而(!IsExit)
{
尝试
{
profiler.RunProfiles(profiles);//这应该等到所有子线程都完成之后
Thread.Sleep(ThreadSleep);//在下一次迭代之前睡眠
}
捕获(例外情况除外)
{
对数误差(ex);
errorCount++;
if(errorCount>10)//如果发生10个严重错误,停止服务
{
IsExiting=true;
打破
}
}
}
}
受保护的覆盖void OnStop()
{
尝试
{
if(探查器!=null)
profiler.IsExiting=true;//在此处设置一个变量以通知所有剩余线程停止
//在这里,它应该等待主线程和子线程完成
base.OnStop();
}
抓住
{
base.OnStop();
}
}
//分析器类
//******************************************************
专用只读信号量_throttle//为允许一次执行的线程数设置限制
公共void运行配置文件(列表配置文件)
{
foreach(配置文件中的var配置文件)
{
if(IsExiting)break;//如果调用退出命令,则停止迭代
_throttle.WaitOne();//等待信号量插槽变为可用
ThreadPool.QueueUserWorkItem(RunProfile,profile);//然后添加到线程队列
}
}
专用void运行配置文件(对象配置文件)
{
尝试
{
var p=(配置文件为配置文件);
if(p==null | | IsExiting)
{
_throttle.Release();//如果找不到配置文件或正在退出,请释放信号量插槽
返回;
}
//****
//做一堆事情
//****
_throttle.Release();//释放信号量插槽
}
捕获(例外情况除外)
{
日志错误(ex);
_throttle.Release();//释放信号量插槽
}
}
如果发生停止事件或某些异常,并且您希望停止服务,我将使用任务(来自.NET 4.0的TPL)并使用CancellationToken来取消任务
但是,如果您想坚持使用信号量或旧的同步原语,那么您的解决方案就可以正常工作
另外,请查看本文:
这里有几个有用的例子可以帮助您选择最佳解决方案。我相信CountdownEvent是高度优化和操作系统无关的,所以从您的列表中,我会选择那个