2010-01-08 3 views
4

Я следил за некоторыми учебниками о том, как создавать аксессоры событий custem. Это код, у меня есть:C# Почему мой оператор блокировки висит?

event ControlNameChangeHandler IProcessBlock.OnControlNameChanged 
{ 
    add 
    { 
     lock (ControlNameChanged) 
     { 
      ControlNameChanged += value; 
     } 
    } 
    remove 
    { 
     lock (ControlNameChanged) 
     { 
      ControlNameChanged -= value; 
     } 
    } 
} 

На данный момент код достигает в надстройке statament lock(ControlNameChanged), ничего не происходит. Код больше не работает. Однако мое приложение все еще работает. Он не замерзает или что-то в этом роде.

Что пошло не так?

+1

Изменение обработчика во время выполнения обработчика - очень плохая идея! –

+0

Как вы это понимаете? Извините, я новичок в этом. – Martijn

+0

@Mitch: больше похоже на направление к делегату или другому событию на том же объекте, поскольку это явная реализация интерфейса. – Lucero

ответ

13

Как-то кто-то держит замок. Вы не должны использовать экземпляры делегатов многоадресной передачи или события для блокировки, и вы также не должны использовать публичных членов, потому что вы не можете контролировать, кто блокирует и когда.

Поэтому я хотел бы использовать отдельный объект запирающий так:

private readonly object controlNameChangedSync = new object(); 

event ControlNameChangeHandler IProcessBlock.OnControlNameChanged 
{ 
    add 
    { 
    lock (controlNameChangedSync) 
    { 
     ControlNameChanged += value; 
    } 
    } 
    remove 
    { 
    lock (controlNameChangedSync) 
    { 
     ControlNameChanged -= value; 
    } 
    } 
} 

Примечание: ссылка на событие изменения при выполнении += или -= на делегата.

+0

Действительно (мой теперь удаленный ответ говорит то же самое, в основном). Текущий код не является потокобезопасным. –

+0

Разве это не подразумеваемая блокировка, если вы не добавляете/удаляете? Если вам не нужно ничего делать при добавлении/удалении, просто дайте C# сделать блокировку. В вашей статье «lockchoice» вы говорите, что рекомендуете wrting-события с добавлением/удалением всегда, но вы не говорите, почему. –

+0

@ Lucero: Я не понимаю. Почему я должен использовать блокировку? Если я прокомментирую инструкцию блокировки, все работает хорошо. Можете ли вы дать мне некоторую справочную информацию о вашем решении? – Martijn

4

и -=изменение делегат. Таким образом, ваши методы «Добавить и удалять» блокируются на разных объектах каждый раз, и у вас вообще нет синхронизации.

Теперь это не объяснит блокировку, но ваш вопрос не очень ясен в отношении того, что на самом деле происходит. Я ожидал, что программа будет выполнять «нормально» с возможностью гонки.

8

Ваш код эквивалентен

event ControlNameChangeHandler IProcessBlock.OnControlNameChanged { 
    add { 
     try { 
      Monitor.Enter(ControlNameChanged); 
      ControlNameChanged = ControlNameChanged + value; 
     } 
     finally { 
      Monitor.Exit(ControlNameChanged); 
     } 
    } 
    remove { 
     try { 
      Monitor.Enter(ControlNameChanged); 
      ControlNameChanged = ControlNameChanged - value; 
     } 
     finally { 
      Monitor.Exit(ControlNameChanged); 
     } 
    } 
} 

Обратите внимание, что объект, который вы выход отличается от того, вы входите. Это означает, что у вас есть один захваченный замок, который никогда не выпускается, и один замок освобождается, но никогда не снимается. Вы должны изменить свой код следующим образом:

private object padlock = new object(); 
event ControlNameChangeHandler IProcessBlock.OnControlNameChanged { 
    add { 
     lock (padlock) { 
      ControlNameChanged += value; 
     } 
    } 
    remove { 
     lock (padlock) { 
      ControlNameChanged -= value; 
     } 
    } 
} 
+0

Отличное объяснение! Не получил его полностью, пока не прочитал свой пост. – leiflundgren