我正在使用Threading.Timer定期在Windows服务中运行一个线程,如下所示:
private Timer _timer;
public void Start()
{
_timer = new Timer(MainLoop, null, 0, Timeout.Infinite);
}
private void MainLoop(object state)
{
// Do something and then tell Timer to wait for a second
_timer.Change(1000, Timeout.Infinite);
}
public void Stop()
{
_timer.Change(Timeout.Infinite, Timeout.Infinite);
}
我的问题是,我希望Windows服务能够监视循环正在运行的线程,并在发现已停止的情况下执行某些操作。
以前我使用的是Thread.Sleep而不是Timer,这意味着所有内容都运行在单个线程中,而不是线程池中的单个线程,我可以查询Thread的ThreadState。现在我正在使用Timer,ThreadState被“停止”,因为一旦Timer启动,Thread就会停止。
那么在使用Threading.Timer时,确认线程是否仍在运行的最佳方法是什么?
答案 0 :(得分:3)
您可以在内容MainLoop
周围添加一个try-finally块,以保证计时器始终重新启动。
private void MainLoop(object state)
{
try
{
// Do something and then tell Timer to wait for a second
}
finally
{
_timer.Change(1000, Timeout.Infinite);
}
}
如果您仍然认为需要监控此方法的执行情况,则可以跟踪方法的上次启动时间。
private void MainLoop(object state)
{
_lastRunTime = DateTime.UtcNow;
try
{
// Do something and then tell Timer to wait for a second
}
finally
{
_timer.Change(1000, Timeout.Infinite);
}
}
然后您可以使用_lastRunTime
并将其与当前时间进行比较,以查看MainLoop
的执行是否挂断或计时器(由于某些不明原因)未重启。
答案 1 :(得分:2)
让线程更新一些Windows服务可见的值,如果值未更新,则表示线程已停止。我不知道监视计时器的任何其他方法
答案 2 :(得分:0)
我采取不同的方法,创建自己的线程并使用回调来表示线程已完成。回调传回主线程用来决定做什么的结果。您甚至不需要计时器来执行此操作,但您可以使用一个计时器使您的工作人员间隔开火。
这是一个使用WaitHandle向主管发出信号已经完成的示例。
class Supervisor
{
EventWaitHandle waitHandle = new AutoResetEvent(false);
public bool Success { get; set; }
// launch worker thread and wait for result
public void Start()
{
while (true)
{
Thread thread = new Thread(() => { new Worker(new DoneDelegate(WorkerDone)).DoWork(); });
thread.IsBackground = true;
thread.Start();
waitHandle.WaitOne(); // wait for worker to finish
if (!Success) break; // handle error here
}
}
// callback for worker to report result
public void WorkerDone(bool successArg)
{
Success = successArg;
// wake up supervisor
waitHandle.Set();
}
}
public delegate void DoneDelegate(bool successArg);
class Worker
{
public DoneDelegate Done { get; set; }
public Worker(DoneDelegate doneArg)
{
Done = doneArg;
}
public void DoWork()
{
// simulate work and exception
Random rnd = new Random();
Thread.Sleep(1000);
try
{
int i = 10 / (1 - new Random().Next(5));
Done(true);
}
catch
{
Done(false);
}
}
}