取代线程.暂停和线程.在windows服务中恢复
本文关键字:线程 服务 恢复 windows 暂停 取代 | 更新日期: 2023-09-27 18:14:24
我们有一个服务,它完成以下基本工作流程:
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.
}