c++multithreadingc++11mutex

Classes and Mutex


Supposed I have a class that represent some data structure called foo:

class foo{
  public:
    foo(){
      attr01 = 0;
    }
    void f(){
      attr01 += 5;
    }
  private:
    int attr01;
};

class fooSingleThreadUserClass{
    void usefoo(){
      fooAttr.f();
    }

    foo fooAttr;
}

Now supposed later in software construction, I found out that I need multithreading. Should I add the mutex in foo?

class foo{
  public:
    foo(){
      attr01 = 0;
    }
    void f(){
      attr01Mutex.lock();
      attr01 += 5;
      attr01Mutex.unlock();
    }
  private:
    int attr01;
    std::mutex attr01Mutex;
};

class fooMultiThreadUserClass{
    void usefoo(){
      std::thread t1(&fooMultiThreadUserClass::useFooWorker, this);
      std::thread t2(&fooMultiThreadUserClass::useFooWorker, this);
      std::thread t3(&fooMultiThreadUserClass::useFooWorker, this);
      std::thread t4(&fooMultiThreadUserClass::useFooWorker, this);

      t1.join();
      t2.join();
      t3.join();
      t4.join();
    }

    void useFooWorker(){
      fooAttr.f();
    }

    foo fooAttr;
}

I know that fooMultiThreadUserClass will now be able to run foo without races in high performance, but will fooSingleThreadUserClass loose performance due to mutex overhead? I would be very intrested to know. Or should I derive fooCC from foo for concurrency purposes so fooSingleThreadUserClas can keep using foo without mutex, and fooMultiThreadUserClass use fooCC with mutexes, as shown below

class fooCC : public foo{
  public:
    foo(){
      attr01 = 0;
    }
    void f(){  // I assume that foo::f() is now a virtual function.
      attr01Mutex.lock();
      foo::f();
      attr01Mutex.unlock();
    }
  private:
    std::mutex attr01Mutex;
};

Also assume that compiler optimization already took care of virtual dispatches. I would like an opinion wether I should use inhertance or simply put the mutex lock in the original class.

I've search through Stackoverflow already, but I guess my question is a little too specific.

Edit: Note, there doesn’t have to be just one argument, the question is meant to be abstract with a class of n argument.


Solution

  • Use an std::lock_guard. The lock_guard takes a mutex in its constructor. During construction, the lock_guard locks the mutex. When the lock_guard goes out of scope, its destructor automatically releases the lock.

    class foo
    {
    private:
      std::mutex mutex;
      int attr01;
    
    public:
      foo() {
        attr01 = 0;
      }
    
      void f(){
        std::lock_guard<std::mutex> lock (mutex);
        attr01 += 5;
      }
    };
    

    You can put mutable on the mutex if you need to be able to lock or unlock the mutex from const functions. I usually leave mutable off the mutex until I specifically need it.

    Will it lose performance? It depends. If you are calling the function a million times then maybe the overhead of creating the mutex will become a problem (they are not cheap). If the function takes a long time to execute and it is called frequently by many threads, then perhaps the rapid blocking will hinder performance. If you can't pinpoint a specific concern, just use std::lock_guard.

    Hans Passant brings up a valid concern that is out-of-scope of your question. I think Herb Sutter (?) wrote about this in one of his website articles. Unfortunately I can't find it right now. To understand why multi-threading is so hard, and why locks on single data fields is "not enough", read a book on multi-threaded programming like C++ Concurrency in Action: Practical Multithreading