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

时间:2011-10-03 04:42:53

标签: c# multithreading locking begininvoke

我有一个带有控件的表单来显示一些自定义对象。在表单中,我订阅了一个事件AddObject,它将对象添加到ToAdd列表中,因为它们是从服务器进入的。我设置了一个计时器,每10秒运行一次,将对象从ToAdd列表复制到显示列表(更有效的是将这些项目批量添加到控件中,而不是一次添加1个),这是绑定到控制我的表格,然后我清除ToAdd列表。将锁定在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(){}
    }

1 个答案:

答案 0 :(得分:1)

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

一些注意事项:

  • List<T>AddRange方法,效率高于多个AddDisplay.AddRange(ToAdd);
  • 一样使用它
  • IntermittentProcessMessages中的委托不在try-catch中,因为BeginInvoke会立即返回。