我正在寻找有关为什么Microsoft建议在编码事件访问器语法时锁定对象的更多信息。下面显示了Microsoft的代码示例,并链接到该建议。
我理解锁定一段代码以控制对它的多线程访问的一般概念,但是我正在寻找在所示示例的上下文中编码自定义事件访问器逻辑时这些问题发挥作用的具体原因Microsoft。
以下示例演示如何实现自定义添加和删除 事件访问器。尽管您可以替换 访问器,我们建议您在添加或之前锁定事件 删除新的事件处理程序方法。
event EventHandler IDrawingObject.OnDraw
{
add
{
lock (PreDrawEvent)
{
PreDrawEvent += value;
}
}
remove
{
lock (PreDrawEvent)
{
PreDrawEvent -= value;
}
}
}
~ 通过 https://msdn.microsoft.com/en-us/library/bb882534.aspx?f=255&MSPPError=-2147217396
只有 MSDN 文章的作者才能为您提供有关文章措辞的明确答案。
但是:在我看来,建议的主要原因是代码几乎总是使用编译器提供的事件访问器方法。这些一直旨在实现 100% 线程安全,并且随着编译器的最新更改(我认为从 C# 4 开始,但我不确定),它们实际上是
。我认为,使默认实现线程安全的原因是不言自明的:这样做涉及相当低的成本,并且事件访问器方法中对线程安全的需求足够频繁,以至于强迫开发人员每次需要线程安全时都实现自己的访问器是不合理的。
因此,鉴于默认实现是线程安全的,这意味着事件的使用者(通常无法随时访问事件的源代码)将习惯于假设事件访问器始终是线程安全的。违反此假设可能会导致代码中包含错误。
底线:如果您 100% 确定您的事件只会在单个线程中访问,或者至少以线程安全的方式访问,则可以在不向访问器方法添加显式线程安全的情况下逃脱。问题是,达到这种100%的确定性的有效性是可疑的;预测一段特定的代码将如何使用几乎是不可能的,尤其是人们正在谈论的更远的未来。
代码可以存活很长时间。最好确保它可以处理抛出的内容,尤其是当代码的未来客户端有充分的理由假设代码可以处理它时。
顺便说一句:虽然 MSDN 显示锁定事件字段本身,但这对我来说似乎是有问题的。当字段更新时,任何当前持有的锁都不会阻止随后执行的代码进入锁,即使锁本身尚未退出也是如此。由于对现场的读取和写入顺序错误,某些平台上可能存在字段可见性问题;这可能导致随后执行的两个线程看到不同的锁值,然后同时进入受保护部分。
不要介意使用公开可用的值进行锁定的更普遍的问题。关于这个特定主题有一些争论,但我更喜欢只使用私有值进行锁定。即不要使用事件字段的当前值锁定(因为它是可更改的),也不要使用this
锁定(因为它是公共的)。