在BeginInvoke调用中使用lock()安全吗?

本文关键字:安全 lock BeginInvoke 调用 | 更新日期: 2023-09-27 18:10:21

我有一个带有控件的表单来显示一些自定义对象。在表单中,我订阅了一个事件AddObject,当对象从服务器传入时,它将对象添加到ToAdd List中。我设置了一个计时器,每10秒运行一次,将对象从ToAdd List复制到Display List(将项目批量添加到控件中比每次添加1个项目更有效),这与我的窗体上的控件绑定在一起,然后清除ToAdd List。把锁放在BeginInvoke里面安全吗?有更好的方法吗?

        private System.Threading.Timer aTimer;
        private readonly Object sync = new Object();
        List<object> ToAdd = new List<object();
        List<object> Display = new List<object();
        private void Init()
        {
           TimerCallback tcb = IntermittentProcessMessages;
           aTimer = new System.Threading.Timer(tcb, null, 1000, 100);
           Server.MessageReceived += AddObject;   
        }
        private void AddObject(object t)
        {
            lock (sync)
            {
                try
                {
                   ToAdd.Add(t);
                }
                finally() {}
            }
         }

        private void IntermittentProcessMessages(object source)
        {
            try
            {
                if (this.IsHandleCreated == false)
                {
                    return;
                }
                this.BeginInvoke((Action)delegate()
                {
                   lock (sync)
                   {
                       if (ToAdd.Count > 0)
                       {
                           ToAdd.ForEach(f => Display.Add(f));
                           ToAdd.Clear();
                       }
                   }
                }
           }
           finally(){}
    }

在BeginInvoke调用中使用lock()安全吗?

是安全的。从技术上讲,锁不在BeginInvoke中,而是在从delegate创建的匿名函数中。

一些注意事项:

  • List<T>有一个AddRange方法,比多个Add更有效。
    Display.AddRange(ToAdd);
  • 一样使用
  • IntermittentProcessMessages中的委托不被try-catch覆盖,因为BeginInvoke立即返回。