【问题标题】:Boolean flag in Windows Service not workingWindows 服务中的布尔标志不起作用
【发布时间】:2018-12-10 15:33:03
【问题描述】:

对不起,我的英语不好,如果有人可以帮助我解决问题,将不胜感激。

我编写了一个 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;            
        }
    }
}

【问题讨论】:

    标签: multithreading windows-services


    【解决方案1】:

    您的代码很容易失败,因为竞争条件存在很大的“机会之窗”。

    考虑这种潜在的情况:

    1. 线程 #1 的计时器已过,ProcessOutwardMessageTimer_Elapsed() 被调用
    2. _isProcessOutwardMessage 为假,因此调用“var processOutwardMessageThread = new Thread(ProcessOutwardMessage)
    3. 当线程 #1(和系统)正在创建新线程(可能需要几毫秒才能完成)时,线程 #2 的计时器开始计时
    4. 线程 #2 发现 _isProcessOutwardMessage 为假,因此它调用“var processOutwardMessageThread = new Thread(ProcessOutwardMessage)”。
    5. 线程#3 和线程#4 最终被创建(分别由线程#1 和线程#2)并且都调用ProcessOutwardMessageWithTransaction()

    你的处理被执行了两次。

    问题在于您检查的位置和设置布尔网守的位置之间的“窗口”太大了。检查和设置网守应尽可能接近单个(原子)操作。检查和设置之间的窗口越大,竞争条件的可能性就越大。

    Synchronization objects 旨在帮助解决该问题。我建议您将它们合并到您的解决方案中。

    【讨论】:

      猜你喜欢
      • 2020-08-18
      • 2018-04-30
      • 2011-10-07
      • 2020-03-04
      • 2018-08-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多