如何正确关闭服务

时间:2014-04-25 08:45:23

标签: c# service

我有一个服务,它始终从队列中读取,我希望服务能够处理在应用程序关闭之前收到的最新项目。我在1-2个月前做过一些研究并找到了一种方法,但它没有用。我的意思是不工作,当服务停止时,它需要99%的CPU,永远不会退出。所以我试图锁定导入函数并锁定close函数,将import设置为false然后继续。同样的事情发生在这里,所以我在导入函数中添加了一个变量,然后在变量为true时进行循环。不用说它不起作用。

public void StopImportSms()
    {
        EventLogger.Write("Waiting for lock to false", EventLogEntryType.Information);
        _import = false;
        while (_lock)
        {

        }
        EventLogger.Write("Import is disabled", EventLogEntryType.Information);

    }

private void ImportSms()
{
while (_import)
    {
        _lock = true;
        var messages = ReadMessages(consumer);

        if (!messages.Any())
        {
            _lock = false;
            continue;
        }
        //Db insert messages
        //Send ack to queue
        _lock = false;
        Thread.Sleep(5);
    }

    public void StartImportSms()
    {
        Task.Factory.StartNew(ImportSms);
    }

1 个答案:

答案 0 :(得分:2)

这是使用事件而不是标志最好解决的问题,因为可以在不使用CPU时间的情况下等待事件(正如您当前的while循环那样)。

我假设第二个代码段是在一个单独的线程中运行的,您不会显示它,所以我将_importThread表示该线程(此Thread对象将需要可以从StopImportSms()方法访问。您还需要声明ManualResetEvent字段:

ManualResetEvent _stopEvent = new ManualResetEvent(false);

然后你的导入循环变为:

while (!_stopEvent.WaitOne(0))
{
    var messages = ReadMessages(consumer);

    // ... further processing here?
}

StopImportSms()更改为:

public void StopImportSms()
{
    EventLogger.Write("Waiting for import to stop...", EventLogEntryType.Information);
    // Instruct the import thread to stop
    _stopEvent.Set();
    // Wait for the thread to complete
    _importThread.Join();
    EventLogger.Write("Import is disabled", EventLogEntryType.Information);
}

修改

由于您为导入方法使用了任务,因此您可能需要尝试以下方法:

在类中声明CancellationTokenSource字段:

CancellationTokenSource _tokenSource = new CancellationTokenSource();

创建导入任务时,请使用以下内容(您需要在实现消息导入循环的方法中添加CancellationToken参数):

var token = _tokenSource.Token;
_importTask = Task.Factory.StartNew(() => ImportMethod(/* other parameters? */ token), token);

然后,实现导入任务的方法更改为:

private void ImportMethod(/* other parameters? */ CancellationToken token)
{
    while (!token.IsCancellationRequested)
    {
        var messages = ReadMessages(consumer);

        // ... further processing here?
    }
}

最后,您的StopImportSms()方法变为:

public void StopImportSms()
{
    EventLogger.Write("Waiting for import to stop...", EventLogEntryType.Information);
    // Instruct the import task to stop
    _tokenSource.Cancel();
    // Wait for the import task to complete
    _importTask.Wait(/* optionally, add a timeout in milliseconds here */);
    EventLogger.Write("Import is disabled", EventLogEntryType.Information);
}

值得注意的是,由于这并未使用CancellationToken.ThrowIfCancellationRequested()方法,因此该任务将表明它已完成运行(即_importTask.Wait()返回后{,{ {1}}将是_importTask.Status,而不是TaskStatus.RanToCompletion)。