3

I'm working on a small project of mine that involves the use of multiple threads.

The C++ STD library offsers different ways to prevent undefined behavior or data races from accessing the same memory block:

  • std::atomic
  • std::mutex with std::lock_guard

Now, from my understanding, you can use both of them and the result would be pretty much the same. Both locks a resource when used by a thread and prevents another from accessing it.

Though, my question is:

When should I prefer to use std::atomic over std::mutex and when should I use std::mutex over std::atomic?


Take this simple class as an example. I have three way of using this class to prevent data races:

Using std::atomic<Buffer>

class Buffer {
  private:
    int m_Data;
  public:
    void Write(int data) {
      m_Data = data;
    }
    int Read() {
      return m_Data;
    }
}

int main() {
  std::atomic<Buffer> buffer;
  buffer.store(Buffer());

  RunThread_0(&buffer, 10);

  RunThread_1(&buffer, 20):
}

Using class member std::atomic<int> m_Data

class Buffer {
  private:
    std::atomic<int> m_Data;
  public:
    void Write(int data) {
      m_Data.store(data);
    }
    int Read() {
      return m_Data.load();
    }
}

int main() {
  Buffer buffer = Buffer();

  RunThread_0(&buffer, 10);

  RunThread_1(&buffer, 20):
}

Using std::mutex and std::lock_guard

class Buffer {
  private:
    int m_Data;

    std::mutex m_DataMutex;

  public:
    void Write(int data) {
      const std::lock_guard<std::mutex> guard(m_DataMutex);
      m_Data = data;
    }
    int Read() {
      const std::lock_guard<std::mutex> guard(m_DataMutex);
      return m_Data
    }
}

int main() {
  Buffer buffer = Buffer();

  RunThread_0(&buffer, 10);

  RunThread_1(&buffer, 20):
}

Note: RunThread_0 and RunThread_1 do what you'd expect: they both call the Buffer::Write method to change the value of member Buffer::m_Data.


Final thoughts

I always used std::mutex and std::lock_guard, but I feel like std::atomic is 'easier' to use as you don't have to worry about missing a lock, whereas if you use std::mutex you can accidentally miss an std::lock_guard statement and thus making a data race possible.

So, is there an advantage in using std::atomic over std::mutex or is it just a design matter?

Diego
  • 133
  • 1
  • 12
  • 3
    In my opinion, C++ `std::atomic` makes sense only for data types that your CPU can process by atomic instructions. Typically, these consists of fundamental integer (including character and Boolean) and pointer types. – Daniel Langr Jan 21 '21 at 08:56

0 Answers0