86

Is there some practical reason why the .NET team decided not to support Boolean in Interlocked.Exchange operation?

One of the usage examples is when you want to guarantee that some code is executed only once and you want to use a Boolean flag for that.

Pang
  • 9,564
  • 146
  • 81
  • 122
Dennis
  • 2,615
  • 2
  • 19
  • 20
  • 5
    you can of course just use an `int` and `if(Interlocked.CompareExchange(ref value, 1, 0)==0) {...}` - doesn't answer the *why* of course... or perhaps easier - `Lazy`: http://msdn.microsoft.com/en-us/library/dd642331.aspx – Marc Gravell May 28 '11 at 22:37
  • Good question, this has been reported to Microsoft many times over the years. I have not seen a satisfactory reason myself other than it being an oversight. If someone knows something let us know! – Brian Gideon May 28 '11 at 23:10
  • If you need Interlocked support for boolean you can use my [InterlockedBoolean.cs](https://gist.github.com/hanswolff/7926751) implementation – quadfinity Dec 12 '13 at 14:23

3 Answers3

81

Yes, there is a good reason. The implementation of the Interlocked methods requires low-level support at the processor level. See this answer for example. That's an issue when you define a framework that's architecture agnostic.

Implementing the low-lock techniques supported by the Interlocked class on data types that are a fraction of the native processor word size is difficult. The RISC approach to cpu design that was popular 10+ years ago discouraged it strongly. The mismatch between operand size and native memory bus width makes it very hard to implement. One reason that Intel's x86 architecture is still on your lap, surviving 30 years already by not taking the shortcuts. More background info on RISC in this wikipedia article.

Community
  • 1
  • 1
Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • 26
    IOW, `InterlockedExchange` doesn't exist for ANY type smaller than 32-bits, and lack of a `bool` overload is just a consequence of this. – Ben Voigt May 29 '11 at 01:21
  • There's no CAS instruction that operates on fewer than 4 bytes so the Interlocked.Exchange overload that worked on a bool (1 byte) would be impossible to implement in a way that had the same cost as the other overloads. I suspect the framework designers want to avoid the confusion that would result. – Jake T. May 29 '11 at 03:17
  • .NET Boolean is 32 bit variable underneith. Interlock operation on it can use the same CPU instruction as one for Int32. – Dennis May 29 '11 at 16:12
  • This answer is misleading. Interloack.Exchange already implemented for Int32 and use platform specific CPU instruction underneath. Implementation for Boolean would use exactly the same instruction. – Dennis May 29 '11 at 16:14
  • 6
    @Dennis: Not true. A bool is only 1 byte. It will get aligned to the native system's word in many cases. It's still only 1 byte, but you can get 3 bytes of padding on a x86 system. – Jake T. May 29 '11 at 18:16
  • 2
    It wouldn't seem that hard to emulate a sub-word CompareExchange. Just read a whole word, check if the part of interest is a mismatch (exit if so), and otherwise figure out its new value, CompareExchange it, and loop as needed until either the CompareExchange succeeds or the portion of interest shows a mismatch. – supercat Jan 21 '13 at 22:42
  • 1
    @supercat That doesn't sound very atomic or lock free. – Bradley Uffner Feb 19 '15 at 18:41
  • @BradleyUffner: It would not be non-blocking, but it would be atomic and lock-free. Atomic because it would not do anything until it could perform the read-modify-write with no interference. Lock-free because progress could not be arbitrarily delayed by having a competing thread get waylaid (if it weren't lock-free and another thread got waylaid while holding the lock, progress would be delayed until that other thread got around to releasing it). Here, if a competing thread gets waylaid, that increases the likelihood of the `CompareExchange` succeeding. – supercat Feb 19 '15 at 18:48
  • 4
    You can't just read a "whole word" for a 1-byte variable. There is no alignment guarantee and you *will* trip an AccessViolationException sooner or later when the byte is the last one in a page. – Hans Passant Feb 19 '15 at 18:56
24

Not answering the question, but as a workaround you can just use int instead of bool the way C does.

    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.

    }

P.S. If there is evidence that read is faster than write then Interlocked.CompareExchange might be better for this case (only one first time and I assume a lot of non first).

ILIA BROUDNO
  • 1,539
  • 17
  • 24
1

if you need a simple solution, you can use the object field to set/get boolean value.

    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);
        }
    }