如何:编写一个只能调用一次的线程安全方法?

sta*_*ica 8 .net c# multithreading interlocked compare-and-swap

我正在尝试编写一个只能调用一次的线程安全方法(每个对象实例).如果之前已调用异常,则应抛出异常.

我想出了两个解决方案.他们都是正确的吗?如果没有,他们有什么问题?

  1. lock:

    public void Foo()
    {
        lock (fooLock)
        {
            if (fooCalled) throw new InvalidOperationException();
            fooCalled = true;
        }
        …
    }
    private object fooLock = new object();
    private bool fooCalled;
    
    Run Code Online (Sandbox Code Playgroud)
  2. Interlocked.CompareExchange:

    public void Foo()
    {
        if (Interlocked.CompareExchange(ref fooCalled, 1, 0) == 1)
            throw new InvalidOperationException();
        …
    }
    private int fooCalled;
    
    Run Code Online (Sandbox Code Playgroud)

    如果我没有弄错的话,这个解决方案具有无锁的优点(在我的情况下似乎无关紧要),并且它需要更少的私有字段.

我也愿意接受合理的意见,哪些解决方案应该是首选的,并且如果有更好的方法可以提出进一步的建议.

the*_*oop 6

您的Interlocked.CompareExchange解决方案看起来最好,并且(正如您所说)是无锁的.它也比其他解决方案复杂得多.锁是非常重量级的,而CompareExchange可以编译成单个CAS cpu指令.我说跟那个一起去.

  • 这种事情是`CompareExchange`是_designed_ for.它使用一个变量,编译为一条CPU指令,并且是一行代码.只要有评论,没有其他线程问题使其复杂化,那么就没有理由不使用它.如果你的任何程序员不明白它的作用,那么他们应该查找它.你不应该愚蠢到他们的水平,他们应该升到你的水平.如果他们不了解原子操作,那么他们应该学习.这就是他们如何变得更好,这是每个人都应该渴望做的事情. (5认同)
  • @stakx:这就是评论的目的。当程序员遇到他们不理解的东西时,他们应该查找它以便他们理解它。这就是他们如何成为更好的程序员。 (2认同)