C# and thread-safety of a bool

35,476

Solution 1

No, not all of them are thread safe.

Case one isn't actually completely thread safe, or better saying - it isn't thread safe at all. Even if operations with boolean are atomic, variable value can be stored in a cache, and so, as in multicore CPU each core has it's own cache, value can be potentially corrupted.

Going even further, compiler and CPU can perform some internal optimizations, including instruction reordering, which can harmfully affect your program's logic.

You can add the volatile keyword, to notify the compiler that this field is used in a multi-threaded context. It will fix problems with cache and instruction reordering, but doesn't give you truly "thread safe" code (as write operations still will be not synchronized). Also volatile cannot be applied to local variable.

So when dealing with multi-threading you always have to use some technique of thread synchronization on valuable resources.

For more information - read this answer, which has some deeper explanation of different techniques. (example there is about int, but is doesn't really matter, it describes general approach.)

Solution 2

A little bit late but should be useful to the others.

You can implement your own thread safe boolean in the following way:

// default is false, set 1 for true.
private int _threadSafeBoolBackValue = 0;

public bool ThreadSafeBool
{
    get { return (Interlocked.CompareExchange(ref _threadSafeBoolBackValue, 1, 1) == 1); }
    set
    {
        if (value) Interlocked.CompareExchange(ref _threadSafeBoolBackValue, 1, 0);
        else Interlocked.CompareExchange(ref _threadSafeBoolBackValue, 0, 1);
    }
}

Be sure to use Property everywhere, never access int variable directly.

Solution 3

Nope, it isn't. But the solution is quite easy. To make a bool (or anything, actually) thread safe, it's easy to use lock statement like this:

object locker = new object();
protected bool _somebool;
public bool Somebool
{
    get
    {
        lock (locker)
            return _somebool;
    }
    set
    {
        lock (locker)
            _somebool = value;
    }
}

Now you may enjoy your thread safe of <T>.

Share:
35,476

Related videos on Youtube

Patryk Golebiowski
Author by

Patryk Golebiowski

Updated on May 09, 2022

Comments

  • Patryk Golebiowski
    Patryk Golebiowski almost 2 years

    I am very confused about this subject - whether reading/toggling a bool value is thread-safe.

        // case one, nothing
        private bool v1;
        public bool V1 { get { return v1; } set { v1 = value; } }
    
        // case two, with Interlocked on set
        private int v2;
        public int V2 { get { return v2; } set { Interlocked.Exchange(ref v2, value); } }
    
        // case three, with lock on set
        private object fieldLock = new object();
        private bool v3;
        public bool V3 { get { return v3; } set { lock (fieldLock) v3 = value; } }
    

    Are all of them thread-safe?

    EDIT

    From what I have read (click) atomicity of bool does not guarantee it will be thread safe. Will then volatile type help?

    • user1703401
      user1703401 about 9 years
      None of these are thread-safe. The thread that calls the getter will always read a stale value. How stale it is depends on the processor and the optimizer. Ranges from a handful of nanoseconds to infinity. The getter needs to synchronize as well. Or you'd use ManualResetEvent/Slim.
    • xanatos
      xanatos about 9 years
      @Ksv3n Assignement is always an atomic operation False, long (64 bit) assignment by a 32 bit program isn't atomic.
    • Patryk Golebiowski
      Patryk Golebiowski about 9 years
      @HansPassant A getter can read an old value, this is understandable. However, how could it last to infinity? Using a lock will make it read the correct value - reread it as if it was volatile? I don't think it works that way, I am confused about what you're saying. I thought that once nobody is writing anymore, the getter will work correctly.
    • user1703401
      user1703401 about 9 years
      It will be infinity when the optimizer stores the backing variable in a processor register and doesn't reload it from memory. Because it doesn't know that another thread can update it. The x86 jitter does that if the bool isn't declared volatile. Example is here.
    • Patryk Golebiowski
      Patryk Golebiowski about 9 years
      Thank you, it is clear now :)
  • xanatos
    xanatos about 9 years
    value can be potentially corrupted No, value can't be corrupted (as in "transform in illegal/undefined value"). You could get stale ("old") values.
  • Yura
    Yura about 9 years
    I mean "corrupted" in a way "not one, that it should be or you expect it to be". Definitely not a corrupted in a sense of memory corruption:)
  • stomy
    stomy almost 5 years
    In the get why not use Interlocked.Read(ref _threadSafeBoolBackValue) == 1 instead of Interlocked.CompareExchange?
  • lilo0
    lilo0 almost 5 years
    Simple, because where is no Interlocked.Read for int parameter. If you really want to use Interlocked.Read method, you may change back value type to long.
  • Justin
    Justin about 3 years
    If I were to make _threadSafeBoolBackValue and ThreadSafeBool static for a class that is static, would thread safety will still valid?
  • lilo0
    lilo0 about 3 years
    @Justin Yes, it will. Interlocked methods didn't distinguish static and instance variables, and static initialization is thread safe. So, I see no problems in this case.
  • user1664043
    user1664043 almost 3 years
    I just started using .Add(ref _threadSafeBoolBackValue, 0) == 1
  • lilo0
    lilo0 almost 3 years
    @user1664043 seems valid as well, good catch. Btw, the set method could also be simplified as Interlocked.Exchange(ref _threadSafeBoolBackValue, value ? 1 : 0);