0

Could somebody tell the reasons why std::mutex is neither copyable nor movable? Somebody told me that it has some relationship to avoid resource waste. Why the copy constructor of std::mutex should be marked as deleted? If not, is there any potential problem? Its copy constructor is clearly marked as deleted, but I have not seen such declaration for its movement constructor. So why does cppreference say std::mutex is not movable?

einpoklum
  • 118,144
  • 57
  • 340
  • 684
John
  • 2,963
  • 11
  • 33
  • 3
    Logically, what would it mean to copy a mutex? What's the difference between that and just creating a mutex from scratch? – Sebastian Redl Jun 14 '20 at 06:59
  • @TonyTannous Sorry, maybe I mislead you.I **fully comprehend** why std::mutex should be not movable. But I still have a question. **Its copy constructor is clearly marked as deleted**, **but I have not seen such a declaration for its movement constructor**. So why does cppreference say std::mutex is not movable? – John Jun 14 '20 at 07:28

3 Answers3

1

Expanding a bit on the other answers, basic locks such as Mutexes are the most basic objects in the language design providing atomic operations, lock and unlock here. These might own an OS implemented handle (native_handle) that is a handle for a hardware implemented object, and might even skip the intermediate handle.

Copying such a handle of course, is non-trivial (you can't copy a piece of hardware, and sometimes even a OS handle, trivially). Moving it is potentially worse - move leaves the object in an unspecified state, but by its nature, a mutex is shared across threads. If you gut it on one thread, you would somehow have to inform all other threads - more likely you would just have breaking code. This is a lot of overhead for no potential benefit (I can see).

As to why the move constructor is not explicitly deleted in your reference - no default move constructor is created if there is a (non-default) defined destructor (12.8, comment 9), so there is no need to delete it.

kabanus
  • 24,623
  • 6
  • 41
  • 74
  • What do you mean by "might even skip the intermediate"? Could you please explain that in more detail? – John Jun 14 '20 at 07:20
  • 1
    @John Some OS might allow compiled programs to directly write instructions to the hardware implementing the atomic operation, instead of giving an OS handle. Anymore than that I think would deserve a new question. – kabanus Jun 14 '20 at 07:21
  • If I understand what you mean correctly, maybe, it is directly implemented by the assembly , so there is no OS handle. Am I right? – John Jun 14 '20 at 07:26
  • @John yes (machine code really), but you are delving way into the deep implementation details that usually don't matter to anyone not implementing a real-time machine themselves. Whether the OS provides a handle or the hardware is directly accessed, the point is ownership cannot be easily copied or moved in a way that makes sense. – kabanus Jun 14 '20 at 07:27
  • Thank you for your clarification. As per the documentation(https://en.cppreference.com/w/cpp/thread/mutex/~mutex), I could only see default `destructor` for `std::mutex`, no user defined `destructor` is declared. Quote from your answer[emphasis mine]:" no default move constructor is created **if there is a (non-default) defined destructor** (12.8, comment 9), so there is no need to delete it." Could you please explain that in more detail. – John Jun 14 '20 at 07:42
  • @einpoklum Added to the answer. – kabanus Jun 14 '20 at 15:44
  • @einpoklum second paragraph - added the part why it wouldn't make sense to have a move constructor in general. In short, synchronization problems with no real added value. – kabanus Jun 14 '20 at 16:01
  • I don't see why a mutex would be different from anything else that's shared between threads. You just need to make sure you don't move the mutex before everyone knows not to use it. – einpoklum Jun 14 '20 at 16:07
  • @einpoklum with no added benefit. This is speculation now, but I feel the standard writers saw no point in adding a move constructor (which must be done explicitly). I can't see good use cases myself. Especially since you're not supposed to handle mutexes yourself. – kabanus Jun 14 '20 at 16:09
0

std::mutex has no copy constructor. If you send a copy, each will lock it's own copy and you don't prevent race-condition. Helping programmers not shoot themselves in the foot.

30.4.1 Mutex requirements

A mutex object facilitates protection against data races and allows safe synchronization of data between execution agents (30.2.5). An execution agent owns a mutex from the time it successfully calls one of the lock functions until it calls unlock.

30.2.5 Requirements for Lockable types [thread.req.lockable]

An execution agent is an entity such as a thread that may perform work in parallel with other execution agents

If you could move, then ownership requirement is broken. And apparently it's already been asked before why std::mutex doesn't have a move constructor?

To add and quote draft on @Kabanus answer to why move is not marked deleted

12.8 Copying and moving class objects [class.copy]

20 If the definition of a class X does not explicitly declare a move assignment operator, one will be implicitly declared as defaulted if and only if

  • []
  • []
  • []
  • X does not have a user-declared destructor
  • []
Tony Tannous
  • 14,154
  • 10
  • 50
  • 86
  • Why the copy ctor of `std::mutex` should be marked as deleted? If not, is there any potential problem? – John Jun 14 '20 at 06:43
  • @John probably to meet the requirements for Lockable. – Tony Tannous Jun 14 '20 at 06:45
  • What about moving, then? – einpoklum Jun 14 '20 at 06:46
  • 1
    @einpoklum `A mutex object facilitates protection against data races and allows safe synchronization of data between execution agents (30.2.5). An execution agent owns a mutex from the time it successfully calls one of the lock functions until it calls unlock.` If you could move, then it contradicts the c++11 working draft. Is it not? – Tony Tannous Jun 14 '20 at 06:46
  • What is an "execution agent"? – einpoklum Jun 14 '20 at 06:48
  • @einpoklum *An execution agent is an entity such as a thread that may perform work in parallel with other execution agents* - 30.4.1.1. Somewhat recursive definition. – kabanus Jun 14 '20 at 06:50
  • @kabanus I think you misunderstand me. I fully comprehend why `std::mutex` should be not movable. But I still have a question. **Its copy constructor is clearly marked as deleted,** **but I have not seen such a declaration for its movement constructor**. So why does *cppreference* say `std::mutex` is not movable? – John Jun 14 '20 at 07:16
  • @John See my answer. Also, the first sentence of your question is what's misleading some of the answerers. – kabanus Jun 14 '20 at 07:20
  • @kabanus I see. I am not a native speaker. :(. I'd reedit it. – John Jun 14 '20 at 07:23
  • @kabanus Thank you for your clarification. As per the documentation(en.cppreference.com/w/cpp/thread/mutex/~mutex), I could only see there is a default destructor for std::mutex, but no user defined destructor is declared. Where am I wrong? – John Jun 14 '20 at 07:50
  • @John I inspected the MSVC definition for mutex and it shows. – Tony Tannous Jun 14 '20 at 08:41
  • @TonyTannous I see. As per the documentation(en.cppreference.com/w/cpp/thread/mutex/~mutex), there is none. You could check it. – John Jun 14 '20 at 09:19
  • @TonyTannous: In that case, your quote does not explain why an std::mutex should not be movable. – einpoklum Jun 14 '20 at 16:07
0

In addition to the answer below, mutex handles cannot be copied at the OS level either. In Windows, you have to create a named mutex and then open a new handle based on that name, for example, intended to be used in a new thread/process and std::mutex never creates named objects. So even if there was a copy constructor, it would be impossible to implement it.

Generally, synchronization objects' semantics are different than some plain other object's, even if they are apparently wrapped in a C++ class

Michael Chourdakis
  • 10,345
  • 3
  • 42
  • 78
  • But what about a move constructor? – einpoklum Jun 14 '20 at 06:46
  • @Michael Chourdakis Quote: "So even if there was a copy constructor, it would be impossible to implement it." Why? Could you please explain that in more detail? Is there any potential problem if a copy ctor is implemented? – John Jun 14 '20 at 06:46
  • There is no API in Windows to copy the mutex. As for moving, it would be possible but why so? It would only lead to bugs. – Michael Chourdakis Jun 14 '20 at 06:47
  • @Michael Chourdakis Why does not provide it? – John Jun 14 '20 at 06:48