Events 在C++/CLI如何定义线程安全事件访问器?

Events 在C++/CLI如何定义线程安全事件访问器?,events,thread-safety,c++-cli,Events,Thread Safety,C++ Cli,代码示例“如何:定义事件访问器方法”位于 似乎在不锁定的情况下对内部pE进行变异。(它看起来不像是Delegate::Combine做了任何可以防止问题发生的神奇事情。)它也做了 void raise() { if (pE != nullptr) pE->Invoke(); } 如果检查和调用()之间的pE更改为null,则会出现问题。我有两个问题: 现有代码不是线程安全的,我说得对吗 因为我想要一个线程安全版本的代码,所以我考虑锁定add和remove函数。使用优化

代码示例“如何:定义事件访问器方法”位于

似乎在不锁定的情况下对内部
pE
进行变异。(它看起来不像是
Delegate::Combine
做了任何可以防止问题发生的神奇事情。)它也做了

void raise() {
   if (pE != nullptr)
      pE->Invoke();
}
如果检查和调用()之间的
pE
更改为
null
,则会出现问题。我有两个问题:

  • 现有代码不是线程安全的,我说得对吗

  • 因为我想要一个线程安全版本的代码,所以我考虑锁定
    add
    remove
    函数。使用优化是否过早

    void raise() {
        MyDel^ handler = pE;
        if (handler != nullptr)
           handler->Invoke();
    }
    
    或者我也应该锁定该函数

  • 与链接页面中的示例不同

    对于自定义事件实现,您需要同步
    添加
    删除
    访问器的想法是正确的。只需在实现周围放置一个互斥体。但是没有必要通过调用
    Delegate::Combine
    然后强制转换来丢弃类型安全性。或者您可以不上锁,如下所示:

    void add(MyDel^ p)
    {
         MyDel^ old;
         MyDel^ new;
         do {
             old = pE;
             new = pE + p;
         } while (old != Interlocked::CompareExchange(pE, new, old));
     }
    
    必要时定义
    删除
    new=pE-p;
    )。您为
    raise
    提供的代码对于自定义事件实现来说非常合适


    总之,该MSDN样本是全部垃圾。实现线程安全的最简单方法是使用自动实现的事件。

    可能重复的Thank:-)出于好奇,侦听器是否有办法确保其
    删除()
    本身的尝试已成功?@seek:while
    循环在成功删除之前不会退出。除非您指的是侦听器是否在订户列表中,否则在这种情况下,事件访问器不会提供任何方式让您返回该信息。但是您当然可以创建一个单独的方法来检查
    new.GetInvocationList()->Count!=old.GetInvocationList()->Count
    是的,我指的是后者。我想知道
    raise()。不过,似乎我们需要将
    p
    标记为volatile,以确保完全正确。