我有一个服务,它始终从队列中读取,我希望服务能够处理在应用程序关闭之前收到的最新项目。我在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);
}
答案 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
)。