如何确保由Windows服务计时器生成的线程在停止Windows服务后完成执行?

3
我正在使用System.Timers.Timer构建一个Windows服务。定时器所执行的任务可能需要几秒钟到几分钟的时间。我希望确保当服务停止时,所有已委托的线程在被处理之前都能完成。
以下是代码,但它不会按照我的期望工作,因为如果Windows服务在运行中停止,当前运行的线程将永远无法完成。
public abstract class AgentServiceBase : ServiceBase
{
    private System.ComponentModel.IContainer components = null;
    private System.Timers.Timer _Timer;
    private string _logPath;
    private const int MAXNUMBEROFTHREADS = 10;
    protected int interval = 25000;
    protected int numberOfAllowedThreads = 2;

    public AgentServiceBase()
    {
        this.InitializeComponent();
        this._logPath = (Path.GetDirectoryName(Assembly.GetAssembly(this.GetType()).CodeBase)).Substring(6).Replace("/", @"\");
    }

    protected override void OnStart(string[] args)
    {
        if (args.Length > 0)
        {
            int.TryParse(args[0], out interval);
        }

        if (args.Length > 1)
        {
            int.TryParse(args[1], out numberOfAllowedThreads);
            if (numberOfAllowedThreads > MAXNUMBEROFTHREADS)
            {
                numberOfAllowedThreads = MAXNUMBEROFTHREADS;
            }
            if (numberOfAllowedThreads == 1)
            {
                numberOfAllowedThreads = 2;
            }
        }

        ThreadPool.SetMaxThreads(numberOfAllowedThreads, numberOfAllowedThreads);

        this._Timer = new System.Timers.Timer();
        this._Timer.Elapsed += new ElapsedEventHandler(PollWrapper);
        this._Timer.Interval = this.interval;
        this._Timer.Enabled = true;

    }

    protected override void OnStop()
    {
        this._Timer.Enabled = false;

        Process currentProcess = Process.GetCurrentProcess();

        foreach (Thread t in currentProcess.Threads)
        {
            t.Join();
        }

    }
    /// <summary>
    protected override void Dispose(bool disposing)
    {
        if (disposing && (components != null))
        {
            components.Dispose();
        }
        base.Dispose(disposing);
    }

    private void InitializeComponent()
    {
        components = new System.ComponentModel.Container();
        this.ServiceName = "Agent Service - Johnhenry";

    }

    private void PollWrapper(object sender, ElapsedEventArgs e)
    {
        try
        {
            this.Poll(sender, e);
        }
        catch (Exception exception)
        {
            string message = this.GetType().FullName + "  - Windows Service Exception\n";
            message += exception.GetNestedExceptionInSingleStringOutput();

            FileHelper.Log(message, this._logPath, "exception", FileHelper.LogFileNameChangeFrequency.DAYLY);
        }
    }

    protected abstract void Poll(object sender, ElapsedEventArgs e);
}

非常感谢,

乔塞佩

更新:

在多次尝试计算当前进程自身线程后,我最终选择了更简单的解决方案,即使用计数器来计算定时器启动并仍在运行的线程数量。基于此,我在主线程上调用Sleep并发出RequestAdditionalTime,直到所有线程都结束。 以下是修订后的2种方法:

    protected override void OnStop()
    {
        this._Timer.Enabled = false;

        while (numberOfRunningThreads > 0)
        {
            this.RequestAdditionalTime(1000);
            Thread.Sleep(1000);
        }

    }



    private void PollWrapper(object sender, ElapsedEventArgs e)
    {
        numberOfRunningThreads++;

        try
        {
            this.Poll(sender, e);
        }
        catch (Exception exception)
        {
            string message = this.GetType().FullName + "  - Windows Service Exception\n";
            message += exception.GetNestedExceptionInSingleStringOutput();

            FileHelper.Log(message, this._logPath, "exception", FileHelper.LogFileNameChangeFrequency.DAYLY);
        }
        finally
        {
            numberOfRunningThreads--;
        }
    }
1个回答

3

理想情况下,我希望不超过所需时间延迟停止。我假设通过使用RequestAdditionalTime,我需要传递一个固定的时间。此外,将RequestAdditionalTime添加到循环中,是否会为每个挂起的线程累计额外的时间?谢谢。 - Giuseppe Romagnuolo
是的 - 它需要固定的时间(以毫秒为单位),并且会累加,因此它取决于您对线程剩余运行时间的良好估计... 您可以在循环之前调用它一次(使用足够大的值适用于所有线程),或者您可以在循环内部调用它,并使用足够小的值适用于一个线程完成... - Yahia

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接