Windows服务中的布尔标志不起作用
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Windows服务中的布尔标志不起作用相关的知识,希望对你有一定的参考价值。
对不起我的英语不好,如果有人能帮我修理,我将不胜感激。
我编写了一个Windows服务来从数据库获取事务并将它们导出到平面文件以通过sftp发送到另一个系统。这项服务已经运行了6个月没有任何问题。我的代码如下:
我使用了一个名为_isProcessOutwardMessage
的布尔变量来检查一个线程是否正在运行以启动一个新线程(processOutwardMessageThread
)。有5个标志和5个这样的线程(但我删除了4个以保持我的帖子简短)
我的问题是:经过大约6个月的运行,IT人员在服务器上做了一些事情(他说它正在加强)。自此更新以来,我的服务遇到了错误。当我检查日志时,我发现同一个线程(例如:processOutwardMessageThread
)已经同时执行了两次(看起来该标志不再起作用了)。这是错误的,因为它只能在前一个线程完成后运行(标志已设置为false)。
我试图重新启动该服务,但它只能在1小时左右正常工作,之后,它会再次导致错误。请给我一些建议。谢谢
using Timer = System.Timers.Timer;
namespace FastOne.Payment.MessageService
{
internal partial class ProcessMessageService : ServiceBase
{
private Timer _processOutwardMessageTimer;
public ProcessMessageService()
{
InitializeComponent();
}
private void LoadConfiguration()
{
try
{
_processOutwardMessageInterval =
int.Parse(ConfigurationManager.AppSettings["ProcessOutwardMessageInterval"]);
//Running flag
_isProcessOutwardMessage = false;
}
catch (Exception exception)
{
ProcessServiceLogger.Error(exception);
}
}
protected override void OnStart(string[] args)
{
//Load configs
LoadConfiguration();
_processOutwardMessageTimer = new Timer(_processOutwardMessageInterval);
_processOutwardMessageTimer.Elapsed += ProcessOutwardMessageTimer_Elapsed;
_processOutwardMessageTimer.Start();
}
private void ProcessOutwardMessageTimer_Elapsed(object sender, ElapsedEventArgs e)
{
if (!_isProcessOutwardMessage)
{
var processOutwardMessageThread = new Thread(ProcessOutwardMessage);
processOutwardMessageThread.Start();
}
}
private void ProcessOutwardMessage()
{
try
{
ProcessOutwardMessageWithTransaction();
}
catch (Exception exception)
{
ProcessOutwardMessageLogger.Info("FAILED! ROLLBACK TRANSACTION!");
ProcessOutwardMessageLogger.Error(exception);
}
}
private void ProcessOutwardMessageWithTransaction()
{
//Set flag to true
_isProcessOutwardMessage = true;
//Do something here
WriteLogToFile("Thread Execute.");
//Set flag to false
_isProcessOutwardMessage = false;
}
}
}
您的代码很容易失败,因为竞争条件存在很大的“机会之窗”。
考虑这种潜在的情况:
- 线程#1的计时器过去,并调用ProcessOutwardMessageTimer_Elapsed()
- _isProcessOutwardMessage为false,因此调用“var processOutwardMessageThread = new Thread(ProcessOutwardMessage)”
- 线程#1(和系统)正在创建新线程,可能需要几毫秒才能完成,而线程#2的计时器将关闭
- 线程#2看到_isProcessOutwardMessage为false,因此它调用“var processOutwardMessageThread = new Thread(ProcessOutwardMessage)”。
- 线程#3和线程#4最终创建(分别由线程#1和线程#2),并且都调用ProcessOutwardMessageWithTransaction()。
您的处理执行两次。
问题是你检查的位置和设置布尔网守的位置之间的“窗口”太大了。检查和设置网守应该尽可能接近单个(原子)操作。检查和设置之间的窗口越大,竞争条件的可能性就越大。
创建Synchronization objects是为了帮助解决这个问题。我建议您将它们合并到您的解决方案中。
以上是关于Windows服务中的布尔标志不起作用的主要内容,如果未能解决你的问题,请参考以下文章