2

Am new to C++ 11 and using threading. I came across a scenario where it's not possible to copy mutex & condition variable objects. The code is like this....

class producer {

   public: 
      producer(mutex m, condition_variable cv) 
      {
           mut = m;    // ERROR
           cvar = cv;   // ERROR
       }

    private:
         mutex mut;
         condition_variable cvar;
}

When trying to copy the variables in constructor it's giving the error. Seems like copy constructor is set to delete for mutex and cv.

Is there a way to overcome that? I want a producer & consumer class and then pass the mutex & cv from the main function.

so basically the call from main function should look like....

int main ()
{
    mutex m;
    condition_variable cv;
    //Initialize mutex & cv
    producer prod(m, cv);
}
eyllanesc
  • 235,170
  • 19
  • 170
  • 241
donguy76
  • 610
  • 3
  • 12
  • 33
  • 1
    Think on the sort of horrors that would come from having multiple copies of a mutex. You could build the insides around something like a shared pointer so that copies all reference the same underlying mutex-guts, but that puts a penalty on everyone who wants to just use a mutex without passing it around. – user4581301 May 19 '19 at 03:00
  • 1
    A mutex is intended to secure a resource. Rather than passing the mutex around, consider encapsulating the resource and the mutex in a class and passing an instance of that class around. At the end of the day you'll have the same problem with mutex being non-copyable, and so to is the encapsulating object, but the intent is better described and you can use the class to prevent access to the resource without acquiring the mutex. – user4581301 May 19 '19 at 03:04
  • How to write your special members when you have a `mutex` data member: https://stackoverflow.com/a/29988626/576911 – Howard Hinnant May 19 '19 at 14:03

3 Answers3

2

No this is not possible. Features were added in C++ to enable this feature (non copying).

If you think about the implementation are you changing somekind of kernel object? Will that be the same. Probably not. This is by design.

2

You'll want to store references or pointers to the mutex and condition_variable.

class producer {
public: 
  producer(mutex & m, condition_variable & cv) 
    : _mut{m}
    , _cvar{cv}
  {
  }

private:
     mutex & mut;
     condition_variable & cvar;
};

You could use std::shared_ptrs, since that lets your instances have strong ownership of the mutex and condition_variable, but this was faster to type.

Stephen Newell
  • 7,330
  • 1
  • 24
  • 28
  • There's a downside to this approach: references cannot be reseated, so `producer` cannot be assigned. May not be an issue depending on your use case. – user4581301 May 19 '19 at 02:56
1

It is impossible by design.

What does it even mean to copy a mutex? What should it do?

Say you wait for a mutex A and some body copies mutex A to mutex B. Do you still wait for A or for B? or for both of them? No. You should still wait for A. So other mutex B cannot be a copy of A. So copying is deleted.

Move operation makes sense, but since mutexes are statically allocated, moving them is impossible without changing their addresses - which becomes a nightmare for whoever is waiting on the mutex. Thus move operation is also deleted.

Same criteria holds true for condition variables.

To overcome these problems, you can use pointers to mutexes and condition variables. Say, store them as std::shared_ptr<std::mutex> and std::shared_ptr<std::condition_variable> if you want a simple design.

ALX23z
  • 4,456
  • 1
  • 11
  • 18