2009-06-24 4 views
5

Является ли реализация ниже потокобезопасной? Если нет, чего я не хватает? Должен ли я иметь ключевые слова volatile? Или замок где-нибудь в методе OnProcessingCompleted? Если да, то где?C#: потокобезопасные события

public abstract class ProcessBase : IProcess 
{ 
    private readonly object completedEventLock = new object(); 

    private event EventHandler<ProcessCompletedEventArgs> ProcessCompleted; 

    event EventHandler<ProcessCompletedEventArgs> IProcess.ProcessCompleted 
    { 
     add 
     { 
      lock (completedEventLock) 
       ProcessCompleted += value; 
     } 
     remove 
     { 
      lock (completedEventLock) 
       ProcessCompleted -= value; 
     } 
    } 

    protected void OnProcessingCompleted(ProcessCompletedEventArgs e) 
    { 
     EventHandler<ProcessCompletedEventArgs> handler = ProcessCompleted; 
     if (handler != null) 
      handler(this, e); 
    } 
} 

Примечание: Причины, почему у меня есть частный случай и явный интерфейс вещь, потому что это абстрактный базовый класс. И классы, которые наследуют от него, не должны делать ничего с этим событием напрямую. Добавлен класс обертку, так что это более понятно =)

+0

(ответил на комментарий) –

ответ

4

Там нет необходимости для частного ProcessCompleted члена быть event - это может быть просто поле: - внутри класса, она всегда идет прямо на поле , так что все равно теряется материал event.

подход вы показали с явной блокировки объекта не более потокобезопасной, чем просто полевую подобные события гораздо (т.е. public event EventHandler<ProcessCompletedEventArgs> ProcessCompleted; - единственное различие заключается в том, что вы не блокировки «это» (что это хорошая вещь - вы должны идеально избежать блокировки на this). .. «переменной обработчик» подход является правильным, но есть еще side-effects you should be aware of

+0

Добавлено почему я использовал частный вопрос-манипулятор и явное событие событий на мой вопрос. Это все еще не нужно? И что вы подразумеваете под этим различием? Открывает ли событие EventHandler событие SomeEvent автоматически? – Svish

+2

Да; полевые события (то есть событие без явного добавления/удаления) имеет встроенный замок (это); см. 10.8.1 в спецификации языка (версия MS); однако это обходит код внутри класса - см. http://marcgravell.blogspot.com/2009/02/fun-with-field-like-events.html; так как событие * private *, добавление/удаление (и, следовательно, блокировка) никогда не используется. Для явной реализации интерфейса код в порядке, и вам нужно будет добавить блокировку самостоятельно, что вы сделали, и, возможно, лучше, чем «lock (this)». Stick с ним; -p –

+0

alrighty =) – Svish

5

вы должны зафиксировать, когда вы запрашиваете обработчик слишком , в противном случае вы не можете иметь последнее значение:

protected void OnProcessingCompleted(ProcessCompletedEventArgs e) 
{ 
    EventHandler<ProcessCompletedEventArgs> handler; 
    lock (completedEventLock) 
    { 
     handler = ProcessCompleted; 
    } 
    if (handler != null) 
     handler(this, e); 
} 

Обратите внимание, что это не предотвращает состояние гонки, когда мы решили, что мы выполним набор обработчиков и , а затем один обработчик отменен. Он все равно будет вызван, потому что мы получили делегат многоадресной передачи, содержащий его, в переменную handler.

Существует не так много, что вы можете сделать по этому поводу, кроме того, что сам хендлер знал, что его больше не следует вызывать.

Это, возможно, лучше просто не попробовать сделать событие потокобезопасным - указать, что подписка должна только изменение в потоке, который поднимет событие.

+0

Вы уверены, что замок необходим? Делегаты неизменны, а assignmend - это атомная операция, поэтому я не думаю, что никакой блокировки не требуется. – TcKs

+0

Смотрите мои комментарии к вашему сообщению. Вам абсолютно необходима блокировка, чтобы сделать его потокобезопасным. –

+0

Да, замки в «добавить» и «удалить» необходимо. Но какая польза от использования «блокировки» в «OnProcessingCompleted»? – TcKs

Смежные вопросы