使用AddHandler时是否需要EnterWriteLock?

时间:2022-02-18 15:17:37

When using a ReadWriteLockSlim for multi-threading support, do I need to EnterWriteLock when using AddHandler?

使用ReadWriteLockSlim进行多线程支持时,使用AddHandler时是否需要EnterWriteLock?

Here are two examples to help illustrate my point:

以下两个例子可以帮助说明我的观点:

AddHandler ClassInstance.Event, New EventHandler(AddressOf Me.Method)  

-or-

Me.ReaderWriterLockSlimInstance.EnterWriteLock()
AddHandler ClassInstance.Event, New EventHandler(AddressOf Me.Method)  
Me.ReaderWriterLockSlimInstance.ExitWriteLock()

1 个解决方案

#1


It may depend on the event; for example, if you are consuming an event from a dll written in C# via a "field-like event", i.e.

这可能取决于事件;例如,如果您通过“类似字段的事件”使用C#编写的dll消耗事件,即

public event EventHandler SomeEvent; // synchronized

(yes I know you asked about VB; I explain this below...)

(是的我知道你问过VB;我在下面解释一下......)

then this is (per the C# language spec) automatically synchronized, so there are no multi-threading issues (and it helps here that delegates are immutable). However, even in the same library, a non-field-like event might not be synchronized - i.e.

然后这是(根据C#语言规范)自动同步,因此没有多线程问题(这里代理是不可变的有帮助)。但是,即使在同一个库中,也可能无法同步非类似字段的事件 - 即

private EventHandler myField;
public event EventHandler SomeEvent { // not synchronized
    add { myField += value; }
    remove { myField -= value; }
}

I know you asked about VB... but you are asking about VB as the comsumer. My point is that it depends on the publisher.

我知道你问过VB ......但你问的是VB作为comsumer。我的观点是,这取决于出版商。

So if you can't control the publisher, then manually synchronizing sounds adviseable if you think that there is a threading risk for this scenario (in most cases, there is no need to synchronize; but if you know this is a threaded area, then synchronizing is sensible).

因此,如果您无法控制发布者,那么如果您认为此方案存在线程风险,则可以手动同步声音(在大多数情况下,不需要同步;但如果您知道这是一个线程区域,那么同步是明智的)。

Also note that a common pattern when raising an event is to take a snapshot:

另请注意,引发事件时的常见模式是拍摄快照:

protected virtual void OnSomeEvent() {
    EventHandler handler = SomeEvent; // assume the "field-like" version
    if(handler!=null) handler(this, EventArgs.Empty);
}

My point here is that it is in theory possible for a subscriber to receive an event even after they think they have unsubscribed, so if extreme cases you might want to handle this manually, perhaps by keeping a flag somewhere (or just exception handling).

我的观点是,理论上订阅者即使在他们认为已经取消订阅之后也可以接收事件,所以如果极端情况你可能想要手动处理,也许是通过在某处保留一个标志(或者只是异常处理)。


As requested, last code fragment in VB (via reflector) for comparison:

根据要求,VB中的最后一个代码片段(通过反射器)进行比较:

Protected Overridable Sub OnSomeEvent()
    Dim handler As EventHandler = Me.SomeEvent
    If (Not handler Is Nothing) Then
        handler.Invoke(Me, EventArgs.Empty)
    End If
End Sub

#1


It may depend on the event; for example, if you are consuming an event from a dll written in C# via a "field-like event", i.e.

这可能取决于事件;例如,如果您通过“类似字段的事件”使用C#编写的dll消耗事件,即

public event EventHandler SomeEvent; // synchronized

(yes I know you asked about VB; I explain this below...)

(是的我知道你问过VB;我在下面解释一下......)

then this is (per the C# language spec) automatically synchronized, so there are no multi-threading issues (and it helps here that delegates are immutable). However, even in the same library, a non-field-like event might not be synchronized - i.e.

然后这是(根据C#语言规范)自动同步,因此没有多线程问题(这里代理是不可变的有帮助)。但是,即使在同一个库中,也可能无法同步非类似字段的事件 - 即

private EventHandler myField;
public event EventHandler SomeEvent { // not synchronized
    add { myField += value; }
    remove { myField -= value; }
}

I know you asked about VB... but you are asking about VB as the comsumer. My point is that it depends on the publisher.

我知道你问过VB ......但你问的是VB作为comsumer。我的观点是,这取决于出版商。

So if you can't control the publisher, then manually synchronizing sounds adviseable if you think that there is a threading risk for this scenario (in most cases, there is no need to synchronize; but if you know this is a threaded area, then synchronizing is sensible).

因此,如果您无法控制发布者,那么如果您认为此方案存在线程风险,则可以手动同步声音(在大多数情况下,不需要同步;但如果您知道这是一个线程区域,那么同步是明智的)。

Also note that a common pattern when raising an event is to take a snapshot:

另请注意,引发事件时的常见模式是拍摄快照:

protected virtual void OnSomeEvent() {
    EventHandler handler = SomeEvent; // assume the "field-like" version
    if(handler!=null) handler(this, EventArgs.Empty);
}

My point here is that it is in theory possible for a subscriber to receive an event even after they think they have unsubscribed, so if extreme cases you might want to handle this manually, perhaps by keeping a flag somewhere (or just exception handling).

我的观点是,理论上订阅者即使在他们认为已经取消订阅之后也可以接收事件,所以如果极端情况你可能想要手动处理,也许是通过在某处保留一个标志(或者只是异常处理)。


As requested, last code fragment in VB (via reflector) for comparison:

根据要求,VB中的最后一个代码片段(通过反射器)进行比较:

Protected Overridable Sub OnSomeEvent()
    Dim handler As EventHandler = Me.SomeEvent
    If (Not handler Is Nothing) Then
        handler.Invoke(Me, EventArgs.Empty)
    End If
End Sub