2

For a object that will be accessed by multiple threads, do I need to have a mutex for its constructor and destructor?

My guess is I need a mutex in the destructor, since it is possible to have one thread accessing the object while another thread deleting the object.

On the other hand, I cannot think of a reason why we need a mutex in the constructor, since there cannot be other threads accessing the object before it is fully constructed.

DiveIntoML
  • 2,347
  • 2
  • 20
  • 36
  • 1
    There's no way to answer this question without understanding your actual use case. For example, if you use a mutex in your destructor, it won't stop child destructors from running (and possibly introducing a race on your vtable). – Stephen Newell Mar 14 '19 at 14:08
  • 2
    when object is constructed or destroyed it must be used by only one thread, otherwise there is a big logic issue. So you do not have to synchronize ctor and dtor. It deosn't have sense. The only synchronization that makes sense is join threads spawned by this object. – Marek R Mar 14 '19 at 14:08
  • If there is a thread waiting to access an object that is in the process of de-initialization, I'd call it a bug. – StoryTeller - Unslander Monica Mar 14 '19 at 14:09
  • 1
    if you put the mutex in the destructor it is too late, you have to make sure earlier that the destructor is called only once. Same for constructor, it should run only once, not only in one thread at a time. Please show an example – 463035818_is_not_an_ai Mar 14 '19 at 14:11
  • @StephenNewell if some method holds a mutex, this means some method is executed and object must be sustained by strong reference, ergo ctor is not executed. Also you can't use object when it is not created yet. – Marek R Mar 14 '19 at 14:11
  • 1
    If you have one thread accessing the object while another thread is deleting the object you have a fundamental design problem. A mutex won't save you. One possibility is that the object gets destroyed, and then the other thread tries to access it. – Pete Becker Mar 14 '19 at 14:30
  • See also https://stackoverflow.com/questions/47459833/does-the-c-memory-model-provide-guarantees-about-the-operations-of-constructor – Raedwald Mar 14 '19 at 14:33

1 Answers1

5

You are unable to share object before it is constructed. If it is not shared, then only one thread uses that. Conclusion there is no need to synchronize anything in constructor (unless you are spawning a new thread).

Now destructor is called only when all strong references are ending their lifetimes. This means that when destructor is executed last strong reference is just clean up. Again this means only one thread is using object so there is no point of synchronizing.

If for some magic reason you will have race condition in constructor or destructor the bug must be in an owner of the object.

The only synchronization I can imagine has sense in destructor is joining threads futures (spawned by this object) or fulfilling promises.

Marek R
  • 32,568
  • 6
  • 55
  • 140
  • "You are unable to share object before it is constructed" -- Is it really like that? Is there a guarantee that the field assignment and object pointer publication have the same ordering from the other thread's point of view in absence of synchronization? – Vlad May 04 '23 at 19:17
  • you are mixing responsibilities. In case you are describing for synchronization is responsible code which constructs an object, no object itself. Race is not in given class level, but on level which uses that class. Classic example `shared_ptr`, its internal data (ref counter) are thread safe, but you have to synchronize variable if you change it. – Marek R May 05 '23 at 07:15
  • Nevertheless, "unable" is a pretty strong statement. "Have to share in a safe way, but it's anyone else's job" would perhaps be more accurate. But even if this is the case, so we have protection of the object pointer with object pointer mutex, and and protection of the object state with another mutex, and object initialization is not protected with any mutex, isn't this a data race and therefore UB? – Vlad May 05 '23 at 07:37
  • Please provide example where it can happen. The cases which I can imagine and it could happen are so extreme and strange that it is not worth considering (for me they are a code-smell). Note also that if you you can have race in constructor then you can situation where mutex (which should be part of object) is not constructed yet and this means there is no tool to synchronize. Anyway for me EOT, since we start arguing. There is saying: "If you are arguing you are loosing". – Marek R May 05 '23 at 11:23
  • Just came to my mind: what if the object is global: https://godbolt.org/z/1r55Tzaqs? For the given example, `Examiner` might as well create a new thread and observe `NeverZero.v` from this thread. – Vlad Jun 12 '23 at 17:59