取代线程.暂停和线程.在windows服务中恢复



我们有一个服务,它完成以下基本工作流程:

1)启动,读取配置设置,并执行一些计算在一个大循环。

2)循环的每次迭代,它都需要能够检查服务是否已被告知停止。它执行数据库获取、计算,然后存储结果。我对代码在SQL事务中做得有多好没有信心,所以在这个阶段,我很高兴地假设我们只在每次迭代开始时检查服务停止。

3)执行所有迭代后,服务"休眠"一段时间。可能是5分钟。可能是12个小时。它需要能够在这个睡眠期间"停止"!

目前这是通过以下方式执行的:

private int threadSleepMinutes = 60;
private readonly Mutex mutTerminateService = new Mutex(false);
private Thread serviceThread;
private Thread serviceStopThread;
// Use this flag to allow the Start op to wait for serviceStopThread
// to get going before continuing to create the main loop thread
private volatile bool stopService = true;
public void Start()
{
    this.serviceStopThread = new Thread(this.RunServiceStopThread);
    this.serviceStopThread.IsBackground = true;
    this.serviceStopThread.Start();
    while (stopService)
    {
        Thread.Sleep(100);
    }
    // Some things renamed to anonymise... you get the idea!
    this.serviceThread = new Thread(this.BigLoopMethod);
    this.serviceThread.IsBackground = true;
    this.serviceThread.Start();
}
public void Stop()
{
    // Release the mutex to terminate the service
    serviceStopThread.Resume();
    // Wait 5s max
    int timeout = 5000;
    while (this.serviceThread.IsAlive && timeout > 0)
    {
        Thread.Sleep(100);
        timeout -= 100;
    }
}
private void RunServiceStopThread()
{
    // To guarantee the same thread takes the mutex
    // and releases it in dot net 4, do both ops in this single thread!
    // Dot net 4 the Start() and Stop() are now usually on different threads.
    mutTerminateService.WaitOne();
    stopService = false;
    // Suspend ourself
    serviceStopThread.Suspend();
    // Release the mutex
    mutTerminateService.ReleaseMutex();
}
public void BigLoopMethod()
{
    try
    {
      do
      {
          bool moreOperationsToGo = true; // Just dummy flags and 'stuff' methods here
          while (moreOperationsToGo && !mutTerminateService.WaitOne(0))
          {
              DoStuff();
          }
          // Using this mutex here to sleep nicely - event driven.
          // Gracefully continues after timeout and gracefully exits if 
          // triggered by the mutex.
      }
      while (!mutTerminateService.WaitOne(this.threadSleepMinutes * 60000));
    }
    catch (Exception ex)
    {
        // Exception handling & logging here
    }
}

现在我得到消息说暂停和恢复是不赞成的。在我的情况下,我确切地知道挂起是在什么代码上运行的,因为调用本身就是挂起它的原因!简历,我很清楚它的作用。这样做的唯一原因是,在dot net 3.5中,互斥锁在Start()和Stop()中工作得很好,但dot net 4.0改变了,因此Start()和Stop()在不同的线程中,并且它们将解决方法标记为过时!

有没有一种好的、不过时的方法来做这件事?

谢谢

除非你正在使用互斥锁进行进程间通信,即从另一个进程中取消你的工作线程-我相信在。net 4.0中有一种更简单的方法来实现具有取消功能的工作线程。您可以使用取消令牌,并等待超时-如果令牌被取消,它将发出信号。完整的解决方案(部分使用您的代码)如下:

using System;
using System.Threading;
class App
{
  static void Main()
  {
    var t = new Test();
    t.Start();
    Thread.Sleep(10000);
    Console.WriteLine("aborting");
    t.Stop();
  }
}
class Test
{
private int threadSleepMinutes = 60;
private Thread serviceThread;
private CancellationTokenSource tokenSource;
public void Start()
{
    // Some things renamed to anonymise... you get the idea!
    this.tokenSource = new CancellationTokenSource();
    this.serviceThread = new Thread(this.BigLoopMethod);
    this.serviceThread.IsBackground = true;
    this.serviceThread.Start();
}
public void Stop()
{
    tokenSource.Cancel();
    // Wait 5s max
    int timeout = 5000;
    if (!serviceThread.Join(timeout))
    {
      serviceThread.Abort();
    }
}
public void BigLoopMethod()
{
    try
    {
      var token = tokenSource.Token;
      do
      {
          int operationsToGo = 4; // Just dummy flags and 'stuff' methods here
          while (operationsToGo > 0 && !token.IsCancellationRequested)
          {
              Console.WriteLine("work");
              Thread.Sleep(1000);//DoStuff();
              operationsToGo--;
          }
          Console.WriteLine("no more work");
      }
      while (!token.WaitHandle.WaitOne(this.threadSleepMinutes * 60000));
    }
    catch (Exception ex)
    {
        // Exception handling & logging here
    }
}
}

你不需要一个"stop"线程。启动方法触发BigLoopMethod的事实就足够了。在stop中所需要的只是给互斥锁发信号,然后用适当的超时加入线程(thread . join()将等待线程停止)。如果您的线程没有在适当的时间内加入以强制终止服务,我建议在健壮性方面使用线程中止。

所以在psuedo代码中:

void Start() 
{
    OpenMutex();
    TakeMutex();
    KickOffMyThread();
}
void Stop();
{
    SignalMutex();
    if (!MyThread.Join(Timeout))
    {
        MyThread.Abort();
        Environment.Exit(1); // Die as thread won't join
    }
}
void MyThread()
{
    while (!TakeMutex(sleeptime)
    {
        DoLongWork();
    }
    //Thread was signalled, exiting.
}

最新更新