【问题标题】:Lock static variable - Timer and Event handler锁定静态变量 - 计时器和事件处理程序
【发布时间】:2016-09-21 06:05:48
【问题描述】:

我有一个类,其中一个方法运行了 X 分钟,而另一个方法调用了一个事件处理程序。这两个都会修改静态列表的状态。

下面是代码

 public class DatabaseOps
 {
  private static Timer timer = null;

  private static IDictionary<int, Model.Process> allProcessDetails = new Dictionary<int, Model.Process>();

  public DatabaseOps()
        {
          if (timer.IsNull())
            {
                timer = new Timer(5000);
                timer.Elapsed += new ElapsedEventHandler(OnTimerElapsed);
                timer.Enabled = true;
                timer.AutoReset = true;
                timer.Start();
            }
        }

        // Timer event
         private async void OnTimerElapsed(object sender, ElapsedEventArgs e)
        {
            foreach (var processDetails in tempAllProcessDetails)
            {
                // Some logic
                allProcessDetails.Remove(processDetails.Key); 
                await Task.Run(() => SendProcess(processDetails.Value));
            }
        }

        // Method invoked from event handler
        public void UpdateProcess(Model.Process processDetails)
        {

            if (!allProcessDetails.ContainsKey(processDetails.ProcessID))
            {
                // Add process to allProcessDetails
                // Some logic
            }
            else
            {
                // Modify existing process in allProcessDetails
                // Some logic
            }
        }
 }

事件处理方法会检查进程,如果存在,它会做一些逻辑,如果进程不存在,那么它会用新的逻辑更新同一个进程。

计时器将每隔 X 间隔运行一次,并将每个进程的当前状态发送到外部系统,并将从allProcessDetails 中删除该进程。

这里我需要确保UpdateProcess中的校验码allProcessDetails.ContainsKey(processDetails.ProcessID)OnTimerElapsed中的删除码allProcessDetails.Remove(processDetails.Key)不冲突

根据我的理解,添加锁将阻止使用相同代码序列创建的另一个线程的访问,但这里字典是由从不同代码序列(计时器和事件处理程序)创建的不同线程访问的

那么,如何防止事件处理程序方法访问当前可以在计时器方法中访问的相同键以进行删除。

【问题讨论】:

  • 不管之前的OnTimerElapsed 已经执行完毕,你真的需要解雇另一个OnTimerElapsed 吗?另外System.Timers.Timer(以及System.Threading.Timer)是多线程计时器,这意味着在线程池线程上执行回调。那么,知道了以上内容,那为什么还需要Task.Run呢?
  • @AlexeyGroshev 我不想在下一个计时器事件之前等待任务完成。此外,Task.Run 之前在计时器事件中实现的逻辑不会花费超过计时器间隔的时间。

标签: c# multithreading timer static locking


【解决方案1】:

只需使用ConcurrentDictionary

 private static IDictionary<int, Model.Process> allProcessDetails = new ConcurrentDictionary<int, Model.Process>();

【讨论】:

    【解决方案2】:

    我想你可以简单地使用ConcurrentDictionary。它是一个线程安全的 Dictionary 它具有相同的构造函数和相同的ContainsKey 方法,但除了Remove 方法之外,您需要使用TryRemove 方法。

    链接:

    https://msdn.microsoft.com/en-us/library/dd287191(v=vs.110).aspx

    https://msdn.microsoft.com/en-us/library/dd997369(v=vs.110).aspx

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-10-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多