为什么Interlocked.Exchange不支持布尔类型?


68

.NET团队决定在Interlocked.Exchange操作中不支持布尔值,是否有一些实际的原因?

使用示例之一是当您想保证某些代码仅执行一次并且您想要为此使用布尔标志时。


4
您当然可以只使用intand if(Interlocked.CompareExchange(ref value, 1, 0)==0) {...},而不能回答为什么当然...或者也许更容易-- Lazy<T>msdn.microsoft.com/en-us/library/dd642331.aspx
Marc Gravell

很好的问题,这多年来已多次报告给Microsoft。我自己没有看到令人满意的理由,除了它是一种疏忽。如果有人知道某事,请告诉我们!
Brian Gideon

如果需要对布尔值的互锁支持,则可以使用我的InterlockedBoolean.cs实现
quadfinity 2013年

Answers:


65

是的,有充分的理由。互锁方法的实现需要处理器级别的低级支持。例如,请参见此答案。当您定义与架构无关的框架时,这就是一个问题。

很难在数据类型上实现Interlocked类支持的低锁定技术,这些数据类型是本机处理器字长的一小部分。十多年前流行的RISC cpu设计方法强烈建议不要这样做。操作数大小和本机内存总线宽度之间的不匹配使实现起来非常困难。英特尔x86架构仍在您身边的原因之一,因为不采用捷径而幸存了30年。维基百科文章中有关RISC的更多背景信息。


21
IOW,InterlockedExchange对于小于32位的任何类型都不存在,并且缺少bool重载只是这种情况的结果。
Ben Voigt

5
@丹尼斯:不是。布尔只有1个字节。在许多情况下,它将与本机系统的词汇保持一致。它仍然只有1个字节,但是在x86系统上,您可以获得3个字节的填充。
杰克·T。

2
模拟一个子词CompareExchange似乎并不难。只需阅读整个单词,检查感兴趣的部分是否不匹配(如果是,则退出),否则找出它的新值,进行CompareExchange,并根据需要循环,直到CompareExchange成功或感兴趣的部分显示不匹配为止。
2013年

1
@supercat听起来不太原子或无锁。
Bradley Uffner

4
您不能只读取一个1字节变量的“全字”。没有对齐保证,并且当字节是页面中的最后一个字节时,您迟早触发AccessViolationException。
汉斯·帕桑

19

不回答问题,但是作为一种解决方法,您可以像C一样使用int代替bool。

    int m_IsFirstTime = 1; // 1 means true 0 means false. 

    void SomeMethod()
    {
        if (1 == Interlocked.Exchange(ref m_IsFirstTime , 0))
            // Do something for the first time.

        else
            // Do something for all other times.

    }

PS:如果有证据表明读取比写入快,那么Interlocked.CompareExchange在这种情况下可能会更好(只有一次是第一次,我认为很多非第一次)。


0

如果需要简单的解决方案,则可以使用object字段设置/获取布尔值。

    private object _isRemoved;
    public bool isRemoved
    {
        get
        {
            object returnVal = Interlocked.CompareExchange(ref _isRemoved, false, null);
            return returnVal != null && (bool)returnVal;
        }
        set
        {
            Interlocked.Exchange(ref _isRemoved, value);
        }
    }
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.