线程安全事件调用

2024-02-26

触发事件时避免竞争条件(在多线程应用程序中)的常见做法是:

EventHandler<EventArgs> temp = SomeEvent;
if (temp != null) temp(e);

"Remember that delegates are immutable and this is why this technique works in theory. However, what a lot of developers don't realize is that this code could be optimized by the compiler to remove the local temp variable entirely. If this happens, this version of the code is identical to the first version, so a NullReferenceException is still possible."

问题(根据本书)是“编译器可以优化此代码以完全删除本地临时变量。如果发生这种情况,此版本的代码与第一个版本相同,因此仍然可能出现 NullReferenceException”

根据 CLR via C#,这是强制编译器复制事件指针的更好方法。

virtual void OnNewMail(NewMailEventArgs e)
{
    EventHandler<NewMailEventArgs> temp =
                          Interlocked.CompareExchange(ref NewMail, null, null);
    if (temp != null) 
        temp(this, e);
}

此处,如果 NewMail 引用为 null,则 CompareExchange 会将其更改为 null;如果 NewMail 不为 null,则不会更改 NewMail。换句话说,CompareExchange 根本不会更改 NewMail 中的值,但它确实以原子、线程安全的方式返回 NewMail 中的值。 杰弗里·里克特 (2010-02-12)。通过 C# 的 CLR(第 265 页)。 OReilly Media - A. Kindle 版。

我使用 .Net 4.0 框架,不确定这如何工作,因为 Interlocked.CompareExchange 需要对位置的引用,而不是对事件的引用。

要么是书上有错误,要么是我理解错了。有人实施过这个方法吗?或者有更好的方法来防止这里的竞争条件?

UPDATE

这是我的错误,iterlocked 代码有效。我只是指定了错误的转换,但根据 Bradley(如下)的说法,在 Windows 上的 .net 2.0 及更高版本中没有必要。


不允许编译器(或 JIT)对其进行优化if/temp离开(在 CLR 2.0 及更高版本中);这CLR 2.0 内存模型 http://msdn.microsoft.com/en-gb/magazine/cc163715.aspx#S5不允许引入从堆读取的内容(规则#2)。

Thus, MyEvent无法读取第二次;的价值temp必须阅读if陈述。

See 我的博文 http://code.logos.com/blog/2008/11/events_and_threads_part_4.html对于这种情况的扩展讨论,以及为什么标准模式很好的解释。

但是,如果您运行在不提供 CLR 2.0 内存模型保证(但仅遵循 ECMA 内存模型)的非 Microsoft CLR(例如 mono)上,或者您运行在 Itanium(众所周知,它具有弱硬件内存模型),您将需要像 Richter 那样的代码来消除潜在的竞争条件。

关于你的问题Interlocked.CompareExchange, 语法public event EventHandler<NewMailEventArgs> NewMail只是用于声明类型私有字段的 C# 语法糖EventHandler<NewMailEventArgs>以及一个公共活动add and remove方法。这Interlocked.CompareExchange调用读取私有值EventHandler<NewMailEventArgs>字段,所以这段代码确实按照 Richter 描述的方式编译和工作;它在 Microsoft CLR 中是不必要的。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

线程安全事件调用 的相关文章

  • strtok() 使用安全吗[重复]

    这个问题在这里已经有答案了 我读到了很多负面的东西strtok 有人说它已经过时 有人说它不是线程安全的 等等 那么真相是什么 我可以使用吗strtok 它是线程安全的吗 Note 我正在使用 Visual C 您可以使用它 它是标准库的一
  • Boost MPI 在监听列表时不会释放资源?

    这是一个后续问题如何释放 boost mpi request https stackoverflow com questions 44078901 how do i free a boostmpirequest 我在监听列表而不是单个项目时
  • C# 异步任务比同步慢

    你知道为什么同步斐波那契方法比异步 等待更快并且比异步任务更快吗 我在每个项目方法上都使用了异步 所以主要是这是一个非常糟糕的方法 Code static int FibonacciSync int number if number 0 r
  • 如何使用c#从数据桶中获取所有文档?

    如何获取数据桶中的所有文档 我尝试过一个示例 但我只能获得一个特定的文档 这是我的代码 CouchbaseClient oclient oclient new CouchbaseClient vwspace data bucket name
  • 无法将参数从 `const char *` 转换为 `char *`

    鉴于此代码 void group build int size std string ips Build the LL after receiving the member list from bootstrap head new memb
  • 选择initializer_list迭代器定义

    Why std initializer list
  • 从内存流播放视频文件

    只是好奇看看这是否可能 我有一个 Windows 应用程序 它从我的电脑上的 avi 文件读取所有字节 然后将其存储在 byte 中 现在我的内存中有 avi 文件 我想直接从内存将其加载到某种视频播放器控件中 我尝试过使用 wmplaye
  • 如何调试.NET Windows Service OnStart方法?

    我用 NET 编写的代码仅在作为 Windows 服务安装时才会失败 该故障甚至不允许服务启动 我不知道如何进入 OnStart 方法 如何 调试 Windows 服务应用程序 http msdn microsoft com en us l
  • 模板与非模板类,跨编译器的不同行为

    我在一些应用程序中使用编译时计数器 它确实很有用 昨天我想用 gcc 编译一个程序 我之前使用的是 msvc 并且计数器的行为在模板类中发生了变化 它在模板类中不再工作 过于简化的代码 Maximum value the counter c
  • ASP.NET MVC 动作过滤器

    有谁知道即使在 CATCH 块中 ActionFilterAttribute 类的 OnResultExecuted 方法是否也会执行 ie CookiesActions public ActionResult Login Usuarios
  • 节点*链表中的下一个

    我是数据结构和算法的新手 我遇到了以下代码 typedef struct node int data node next 谁能告诉我为什么我们要声明节点 next next 不能声明为 int next 吗 因为你希望能够做到n gt ne
  • 如果finally 块包含await,为什么*有时*不会在ThreadAbortException 上执行?

    UPDATE 我不认为这个问题是重复的ThreadAbortException最后可以跳过吗 https stackoverflow com questions 18002668 can threadabortexception skip
  • 使用 cmake 将两种解决方案合二为一

    我有两个单独的 Visual Studio 2013 解决方案 我想将它们迁移到一个解决方案中 因为第一个解决方案 使用 Qt 充当第二个解决方案的 GUI 最后 我希望有一个结构如下的单一解决方案 Solution All Build P
  • 意外的 const 引用行为

    include
  • 如何释放字符串未使用的容量

    我正在程序中处理很多字符串 这些字符串数据在读入我的程序后的整个生命周期内都不会改变 但由于 C 字符串保留了容量 因此浪费了大量肯定不会被使用的空间 我尝试释放这些空间 但没有成功 以下是我尝试过的简单代码 string temp 123
  • 展开 std::reference_wrapper 的成本

    Given include
  • 使用C标准数学库精确计算标准正态分布的CDF

    标准 C 数学库不提供计算标准正态分布 CDF 的函数 normcdf 然而 它确实提供了密切相关的函数 误差函数 erf 和互补误差函数 erfc 计算 CDF 的最快方法通常是通过误差函数 使用预定义常量 M SQRT1 2 来表示 d
  • 强制函数调用的顺序?

    假设我有一个抽象基类 并且我想要一个必须由派生类实现的纯虚方法 但我想确保派生方法以特定顺序调用函数 我可以做什么来强制执行它 I E base class virtual void doABC 0 virtual void A 0 vir
  • 在 C# 中使用自定义千位分隔符

    在显示字符串时 我尝试不使用 字符作为千位分隔符 而是使用空格 我想我需要定义一种自定义文化 但我似乎做得不对 有什么指点吗 例如 将 1000000 显示为 1 000 000 而不是 1 000 000 no String Replac
  • 创建进程默认浏览器

    我目前正在使用 ShellExecute 打开 在用户浏览器中打开 URL 但在 Win7 和 Vista 中遇到了一些麻烦 因为该程序作为服务运行提升 我想获取线程 id 因此 ShellExecute 无法获取线程 id 因此我开始使用

随机推荐

  • 将多个单选按钮绑定到单个布尔值

    背景 我有一个包含三个布尔值的模型 public class PageDataModel public bool setting1 get set public bool setting2 get set public bool setti
  • 附加!在计划中?

    我目前正在学习 R5RS 方案 来自 PocketScheme 我发现我可以使用内置于方案的某些变体 但不是全部 中的函数 Append 换句话说 破坏性地改变列表 我对实际代码并不感兴趣 而是对答案感兴趣 而是对将列表作为函数 或向量或字
  • CSS3 文本阴影效果与 jQuery

    我希望能够创建与 CSS3 text shadow 属性相同的效果 使其可供不支持此 CSS3 属性的浏览器 例如 IE 7 和 8 使用 所以我找到了两个插件 文字阴影 https web archive org web 20141108
  • Qt:无法从输入设备读取:没有这样的设备

    我有一个在嵌入式 Linux 平台 i Mx 6 上运行的 Qt 应用程序 我的应用程序应支持触摸屏作为主要输入设备和可选的 USB 键盘 如果已连接 所以现在 我已配置要启动的应用程序 如下所示 my qt app plugin tsli
  • 可更新的 VIEW 不适用于 Postgres 9.5 中的 ON CONFLICT

    PostgreSQL 版本 9 5 4 我有一个表定义为 CREATE TABLE IF NOT EXISTS TEST 1 ID SERIAL PRIMARY KEY C1 BYTEA C2 TEXT NOT NULL C3 BOOLEA
  • 如何从多维数组中找到最大的数组[重复]

    这个问题在这里已经有答案了 可能的重复 获取多维数组中元素的最大值 https stackoverflow com questions 2189479 get the maximum value from an element in a m
  • 获取 Instagram 访问令牌

    我们有一个客户 他的网站上有一个简单的 Instagram 功能 可以按特定标签提取照片 他们只是注意到它不起作用 收到错误 访问令牌无效 我想从一号开始就因为更新了 我们过去不需要访问令牌 因为我们没有对用户做任何事情 只是标签 现在看来
  • Nuxt.js - 在页面中添加两个布局

    我是初学者Nuxt js我正在将 Vue 项目转换为 Nuxt js 并且我想在一个页面上使用两种布局 默认的一个和另一个 逻辑是这样的 第一个布局是 默认 或所有页面上的标题 第二个布局是设置栏 In settings我的页面有 3 条路
  • Vue3 + Vite + Typescript:作用域插槽类型错误

    我有一个包含以下 devstack Vue3 Vite TypeScript 的项目 并且出现以下错误v slot Element implicitly has an any type because expression of type
  • 河内塔序言

    您好 我在实施河内塔时遇到问题 我需要打印包含必要动作的列表列表 但我的算法仅在光盘数量为 N 1 时才起作用 这是我的代码 move 1 X Y L append X Y L move N X Y Z N gt 1 M is N 1 mo
  • javascript 源映射:将映射文件保留在本地,仅用于调试生产 javascript

    我想调试生产网站 但我不想将地图文件上传到服务器上 出于隐私原因 因为它是公开的 对吧 是否可以 我不相信目前任何浏览器都允许从本地文件按需加载源映射 因此您必须以某种方式将源映射放到网上 一种解决方案可能是创建一个 htaccess 文件
  • Angular:拦截 HTTP 错误并继续链

    我想将某些 HTTP 错误代码视为非错误 并正常处理它们的响应 所以我尝试添加一个HttpInterceptor捕获 500 个状态代码 并返回原始响应 Angular 将其放入error error intercept req HttpR
  • 即使类型不可能实现特征,它是否是报告“特征实现冲突”的编译器限制?

    当试图回答时这个问题 https stackoverflow com questions 55628334 trait function conditional default implementation 我写了这段代码 trait My
  • 如何实现XMPP发送推送通知

    我想使用 XMPP 以便我的应用程序能够向 Android 手机 1 5 及更高版本 发送更新 我非常想使用 XMPP 向手机发送推送通知 我将如何实现这一目标 目前 我的 Web 应用程序正在 apache tomact 上运行 带有许多
  • 如何为 Stripe 结帐会话生成已付款发票 PDF?

    目前 我的网络应用程序在通过 Stripe 结账购买后 会通过电子邮件向客户发送 Stripe 收据 然而 对于某些客户来说 这还不够 他们想要一张已付款的购买发票 上面有我的企业和他们的企业的信息 如何使用这些信息生成 PDF 我调查过
  • 不允许出现重复的“row.names”错误

    我正在尝试加载一个包含 14 列的 csv 文件 如下所示 StartDate var1 var2 var3 var14 当我发出这个命令时 systems lt read table http getfile pl test csv he
  • 在 pandas 中解析 POSIX 时间戳的惯用方法?

    我有一个 csv 文件 其中的时间列表示 POSIX 时间戳 以毫秒为单位 当我在 pandas 中读取它时 它正确地将其读取为 Int64 但我想将其转换为 DatetimeIndex 现在我首先将其转换为日期时间对象 然后将其转换为 D
  • 如何以编程方式获取 Android 上的所有热量信息(CPU [所有核心]、GPU、设备等)?

    我正在尝试以编程方式提取 Android 应用程序中的热信息 但没有足够的文档来执行此操作 我想要提取的东西是这样的 vbal low 37 9 C gold virt max step 28 2 C cpu3 银 lowf 27 8 C
  • 用默认值初始化成员的最优雅的方法

    有什么方法可以利用初始化列表来可选地初始化可选 构造函数中的参数 下面的例子诉诸于if x 类型 正文中的逻辑 因为尚不清楚如何设置 x仅在初始化列表中 如果传入的话 class Point double x 0 0 double get
  • 线程安全事件调用

    触发事件时避免竞争条件 在多线程应用程序中 的常见做法是 EventHandler