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

时间:2012-07-20 19:55:06

标签: events thread-safety c++-cli

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

http://msdn.microsoft.com/en-us/library/dw1dtw0d.aspx

似乎在没有锁定的情况下改变内部pE。 (看起来Delegate::Combine没有任何可以防止问题的神奇事物。)它也可以

void raise() {
   if (pE != nullptr)
      pE->Invoke();
}

如果pE在支票和null之间更改为Invoke(),则可能会出现问题。我有两个问题:

  1. 我是否认为现有代码不是线程安全的?

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

    void raise() {
        MyDel^ handler = pE;
        if (handler != nullptr)
           handler->Invoke();
    }
    

    或者我也应该锁定该功能?

1 个答案:

答案 0 :(得分:1)

All three accessors are thread-safe by default (raise includes a null-check, and uses a local variable to avoid the race condition)与您关联的网页中的示例不同。

在自定义事件实现方面,您需要同步addremove访问者。只需在实现中放置一个互斥锁即可。但是,没有必要通过调用Delegate::Combine然后转换since operator + and - are overloaded for delegate handles来抛弃类型安全。或者你可以无锁,如下:

void add(MyDel^ p)
{
     MyDel^ old;
     MyDel^ new;
     do {
         old = pE;
         new = pE + p;
     } while (old != Interlocked::CompareExchange(pE, new, old));
 }

定义remove经过必要的修改(new = pE - p;)。您为raise提供的代码对于自定义事件实现完全没问题。

总之,MSDN示例是完全垃圾。实现线程安全的最简单方法是使用自动实现的事件。