首页 > 解决方案 > 为什么windows服务OnStart()中的Task.Run()会导致服务拒绝停止?

问题描述

我不确定为什么这项服务拒绝停止。

我在尝试纠正TimeoutException启动服务时抛出的问题时遇到了这个问题。使用:

public void OnStart()
{
    _startTask = Task.Run(DoWork, _cancelTokenSource.Token);
}

private void DoWork(){ [listen for things and operate on them] }

public void OnStop()
{
    _cancelTokenSource.Cancel();
    _startTask.Wait();
}

我知道实现一个简单的计时器可以解决这个问题,但这不是我的问题的重点。为什么使用Task.Run(() => action, _tokenSource.Token)resolve the TimeoutExceptionbut会导致服务不响应控制消息?

观察到的问题

安装并启动服务(它是TopShelf BTW)后,我无法通过常规方法停止服务。

第一次尝试:

在此处输入图像描述

所有后续尝试:

在此处输入图像描述

编辑:仍然没有快乐

这是我在遵循提供的示例之后的尝试。

public void Start()
{
    var token = _cancelTokenSource.Token;
    Task.Factory.StartNew(() => Setup(token), token);
}

public void Stop()
        {
            _cancelTokenSource.Cancel();
            //TearDown(); <-- original implementation of stop
        }

private void Setup(CancellationToken token)
        {
            _mailman.SendServiceStatusNotification(_buildMode, "Started");
            ... create some needed objects

            token.Register(TearDown);

            InitializeInboxWatcherProcess(...);

        }

private void TearDown()
        {
            _inboxWatcher.Terminate();
            _mailman.SendServiceStatusNotification(_buildMode, "Stopped");
        }

private void InitializeInboxWatcherProcess(...)
        {
            // pre create and initiate stuff
            _inboxWatcher = new LocalFileSystemWatcherWrapper(...);
            _inboxWatcher.Initiate();
        }

public class LocalFileSystemWatcherWrapper : IFileSystemWatcherWrapper
    {
        // do FileSystemWatcher setup and control stuff
    }

标签: c#windows-servicestask-parallel-librarytopshelf

解决方案


这很可能是因为您没有取消方法,或者DoWork()当您调用Cancel(). 正如@Damien_The_Unbeliever 所说,取消是一项合作任务。

如果您还没有注册回调函数,那么当您调用_cancelTokenSource.Cancel()时,所有发生的事情都是布尔值isCancellationRequested设置为 true,DoWork()然后该方法负责查看并自行停止其执行。DoWork()但是,这里有一个缺陷,您可能会说,如果您在调用时在任务中运行了一个耗时的循环Cancel(),则该循环必须完成一次迭代,然后才能检查isCancellationRequested可能导致挂起的值.

解决这个问题的方法是在方法中插入取消回调函数DoWork(),请参见此处,然后将它们注册到令牌中,这样当您调用该Cancel()方法时,后台运行的所有任务都将停止,而无需等待它们。

希望这可以帮助!


推荐阅读