C# 如何在不使用计时器的情况下在 Windows 服务中进行循环

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2032808/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 22:52:10  来源:igfitidea点击:

How to have a loop in a Windows service without using the Timer

c#windows-services

提问by Chakra

I want to call a Business layer method from a Windows service (done using C# and .NET) after every 10 seconds. However, i dont want to use the Timer_Elapsed event since it starts up another thread/process if the first thread/process is still running. I just need a single threaded approach, since multiple calls to the same Business method creates unwanted complications.

我想在每 10 秒后从 Windows 服务(使用 C# 和 .NET 完成)调用业务层方法。但是,我不想使用 Timer_Elapsed 事件,因为如果第一个线程/进程仍在运行,它会启动另一个线程/进程。我只需要一种单线程方法,因为对同一个 Business 方法的多次调用会造成不必要的并发症。

So i added a do--while loop in the on_start. I know this is not the correct way since it spawns this process which becomes an orphan if the service is shut down.

所以我在 on_start 中添加了一个 do--while 循环。我知道这不是正确的方法,因为它会产生这个进程,如果服务关闭,该进程将成为孤儿。

How can i approach this problem ?

我该如何解决这个问题?

Regards, Chak

问候, 查克

采纳答案by Hans Passant

There's another way to get timed execution, the WaitHandle.WaitOne() method provides a timeout argument. That works very nicely in a service as it lets you implement the need to stop the service andperiodic execution in a single method call. The template looks like this:

还有另一种获得定时执行的方法,WaitHandle.WaitOne() 方法提供了一个超时参数。这在服务中非常有效,因为它允许您在单个方法调用中实现停止服务定期执行的需要。模板如下所示:

    Thread Worker;
    AutoResetEvent StopRequest = new AutoResetEvent(false);

    protected override void OnStart(string[] args) {
        // Start the worker thread
        Worker = new Thread(DoWork);
        Worker.Start();
    }
    protected override void OnStop() {
        // Signal worker to stop and wait until it does
        StopRequest.Set();
        Worker.Join();
    }
    private void DoWork(object arg) {
        // Worker thread loop
        for (;;) {
            // Run this code once every 10 seconds or stop right away if the service 
            // is stopped
            if (StopRequest.WaitOne(10000)) return;
            // Do work...
            //...
        }
    }

回答by Mitch Wheat

Use a timer, but as soon as you enter the Timer handler method, disable the timer so that no more events are raised. Just before exiting the handler, re-enable the timer.

使用计时器,但一旦您进入 Timer 处理程序方法,请禁用计时器,以便不再引发更多事件。在退出处理程序之前,重新启用计时器。

回答by Anders Fjeldstad

Check out this discussion, and in particular the answer by jsw. It suggests a synchronization mechanism to prevent multiple simultaneous calls to the business logic. Just disabling the timer in the Elapsedhandler method isn't guaranteed to prevent parallel calls since the handler is invoked on a separate thread. Use a lock as jsw suggests, and stop the timer within the synchronized code block.

看看这个讨论,特别是jsw的答案。它提出了一种同步机制来防止对业务逻辑的多个同时调用。仅禁用Elapsed处理程序方法中的计时器并不能保证防止并行调用,因为处理程序是在单独的线程上调用的。使用 jsw 建议的锁,并在同步代码块中停止计时器。

Alternatively, you could use a Timerand set the AutoResetproperty to false. That way, the Elapsedevent is raised only once and you can reset the timer manually towards the end of the handler method.

或者,您可以使用 aTimer并将AutoReset属性设置为false。这样,Elapsed事件只引发一次,您可以在处理程序方法结束时手动重置计时器。

回答by user885959

while(true)
    {
     ..do something
     Thread.sleep( some time or day);
    }

回答by moldovanValerian

    Thread thread;
    private void DoWork(object arg)
    {
        while (true)
        {
            // Run this code once every 20 seconds or stop if the service is stopped
            try
            {
                Thread.Sleep(20000);
                //Do work....
            }
            catch(ThreadInterruptedException)
            {
                return;
            }

        }
    }

    protected override void OnStart(string[] args)
    {
        // Start the thread
        thread = new Thread(DoWork);
        mWorker.Start();
    }

    protected override void OnStop()
    {
        // interrupt thread and wait until it does
        thread.Interrupt();
        thread.Join();
    }