Безопасно ли использовать lock () внутри вызова BeginInvoke? - PullRequest
0 голосов
/ 03 октября 2011

У меня есть форма с элементом управления для отображения некоторых пользовательских объектов.В форме я подписываюсь на событие AddObject, которое добавляет объекты в список ToAdd по мере их поступления с сервера.Я установил таймер для запуска каждые 10 секунд для копирования объектов из списка ToAdd в список отображения (было более эффективно добавлять элементы в элемент управления навалом, чем 1 за один раз, когда они поступали), который привязанконтроль в моей форме, затем я очищаю список добавлений.Безопасно ли иметь блокировку внутри 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 Ответ

1 голос
/ 03 октября 2011

Да, это безопасно. Технически блокировка не в BeginInvoke, а в анонимной функции, которая создается из delegate.

Некоторые заметки:

  • List<T> имеет метод AddRange, который более эффективен, чем множественный Add.
    Используйте это как Display.AddRange(ToAdd);
  • Делегат в IntermittentProcessMessages не распространяется на try-catch, поскольку BeginInvoke возвращается немедленно.
...