简体   繁体   English

编码事件访问器时的多线程问题

[英]Multi-threaded concerns when coding event accessors

I'm looking for additional information about why Microsoft recommends locking on the object when coding event accessor syntax. 我正在寻找有关Microsoft在编码事件访问器语法时建议锁定对象的原因的其他信息。 Microsoft's code example is shown below and the recommendation is linked to. Microsoft的代码示例如下所示,建议链接到。

I understand the general concept about locking over a section of code to control multi-threaded access to it, however I'm looking for the specific reason why those concerns come into play when coding custom event accessor logic in context of Microsoft's example shown. 我理解锁定一段代码以控制对它的多线程访问的一般概念,但是我正在寻找在微软示例的上下文中编写自定义事件访问器逻辑时这些问题发生的具体原因。

The following example shows how to implement custom add and remove event accessors. 以下示例显示如何实现自定义添加和删除事件访问器。 Although you can substitute any code inside the accessors, we recommend that you lock the event before you add or remove a new event handler method. 虽然您可以替换访问器中的任何代码,但我们建议您在添加或删除新的事件处理程序方法之前锁定事件。

event EventHandler IDrawingObject.OnDraw
    {
        add
        {
            lock (PreDrawEvent)
            {
                PreDrawEvent += value;
            }
        }
        remove
        {
            lock (PreDrawEvent)
            {
                PreDrawEvent -= value;
            }
        }
    }

~ via https://msdn.microsoft.com/en-us/library/bb882534.aspx?f=255&MSPPError=-2147217396 〜通过https://msdn.microsoft.com/en-us/library/bb882534.aspx?f=255&MSPPError=-2147217396

Only the author of the MSDN article can provide you a definitive answer as to the wording of the article. 只有MSDN文章的作者可以为您提供关于文章措辞的明确答案。

However: it seems to me that the primary reason for the advice is that code almost always uses the compiler-provided event accessor methods. 但是:在我看来,建议的主要原因是代码几乎总是使用编译器提供的事件访问器方法。 These have always been intended to be 100% thread safe, and with a recent change in the compiler (I think as of C# 4, but I don't recall for sure), they actually are. 这些一直是100%线程安全的,并且随着最近编译器的变化(我认为从C#4开始,但我不记得肯定),它们实际上是。

The reasons for making the default implementation thread-safe is, I think, self-explanatory: doing so involves reasonably low cost, and the need for thread-safety in event accessor methods is frequent enough that forcing developers to implement their own accessors every time they need thread safety would be unreasonable. 我认为使默认实现线程安全的原因是不言自明的:这样做涉及相当低的成本,并且事件访问器方法中对线程安全的需求足够频繁,迫使开发人员每次都实现自己的访问器他们需要线程安全是不合理的。

So, given that the default implementation is thread-safe, this means that consumers of events (who often will not have ready access to the source code of the event) are going to be in the habit of assuming that event accessors are always thread-safe. 因此,鉴于默认实现是线程安全的,这意味着事件的消费者(通常无法准备访问事件的源代码)将习惯于假设事件访问器始终是线程的 -安全。 Violating this assumption can lead to code with bugs in it. 违反此假设可能会导致代码中出现错误。

Bottom line: if you are 100% sure your event will only ever be accessed in a single thread, or at least in a thread-safe way, you can get away without adding explicit thread-safety to the accessor methods. 结论:如果您100%确定您的事件只能在一个线程中访问,或者至少以线程安全的方式访问,那么您可以在不向访问器方法添加显式线程安全的情况下离开。 The problem is that arriving at this 100% certainty is of dubious validity; 问题是,达到这种100%的确定性是有道理的; it's nearly impossible to predict how a particular piece of code will be used, especially the farther into the future one is talking about. 几乎不可能预测一段特定代码将如何被使用,尤其是未来人们正在谈论的更远的代码。

Code can live for a surprisingly long time. 代码可以存在相当长的时间。 Best to make sure it can handle what's thrown at it, and especially when future clients of the code have every reason to assume the code can handle it. 最好确保它可以处理它所引发的内容,特别是当代码的未来客户完全有理由认为代码可以处理它时。


As an aside: while the MSDN shows locking on the event field itself, this seems problematic to me. 顺便说一句:虽然MSDN显示事件字段本身的锁定,但这对我来说似乎有问题。 The moment the field has been updated, any currently held lock is going to not prevent subsequently executing code from entering the lock, even if the lock itself hasn't been exited. 字段更新后,任何当前保持的锁定都不会阻止随后执行代码进入锁定,即使锁定本身尚未退出。 There could be field visibility issues on some platforms, due to misordering of reads and writes to the field; 由于对字段的读写错误,某些平台上可能存在字段可见性问题; this could lead to two subsequently executing threads seeing different values for the lock, and then entering the protected section concurrently. 这可能导致两个随后执行的线程看到锁的不同值,然后同时进入受保护的部分。

Never mind the more general problem of using publicly available values for locking. 不要介意使用公开可用值进行锁定的更普遍的问题。 There is some debate on that particular topic, but it is my preference to only ever use private values for locking. 关于该特定主题存在一些争论,但我倾向于仅使用私有值进行锁定。 Ie don't lock using the event field's current value (because it's changeable) and don't lock using this (because it's public). 即不使用事件字段的当前值锁定(因为它是可更改的)并且不使用this锁定(因为它是公共的)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM