Suppose you have an object which can be accesed by many threads. A critical section is used to protect the sensitive areas. But what about the destructor? Even if I enter a critical section as soon as I enter the destructor, once the destructor has been called, is the object already invalidated?
My train of thought: Say I enter the destructor, and I have to wait on the critical section because some other thread is still using it. Once he is done, I can finish destroying the object. Does this make sense?
In general, you should not destroy an object until you know that no other thread is using it. Period.
Consider this scenario, based on your 'train of thought':
Thread A: Get object X reference
Thread A: Lock object X
Thread B: Get object X reference
Thread B: Block on object X lock
Thread A: Unlock object X
Thread B: Lock object X; unlock object X; destroy object X
Now consider what happens if the timing is slightly different:
Thread A: Get object X reference
Thread B: Get object X reference
Thread B: Lock object X; unlock object X; destroy object X
Thread A: Lock object X - crash
In short, object destruction must be synchronized somewhere other than the object itself. One common option is to use reference counting. Thread A will take a lock on the object reference itself, preventing the reference from being removed and the object being destroyed, until it manages to increment the reference count (keeping the object alive). Then thread B merely clears the reference and decrements the reference count. You can't predict which thread will actually call the destructor, but it will be safe either way.
The reference counting model can be implemented easily by using boost::shared_ptr or std::shared_ptr; the destructor will not run unless all shared_ptrs in all threads have been destroyed (or made to point elsewhere), so at the moment of destruction you know that the only pointer to the object remaining is the this pointer of the destructor itself.
Note that when using shared_ptr, it's important to prevent the original object reference from changing until you can capture a copy of it. Eg:
std::shared_ptr<SomeObject> objref;
Mutex objlock;
void ok1() {
objlock.lock();
objref->dosomething(); // ok; reference is locked
objlock.unlock();
}
void ok2() {
std::shared_ptr<SomeObject> localref;
objlock.lock();
localref = objref;
objlock.unlock();
localref->dosomething(); // ok; local reference
}
void notok1() {
objref->dosomething(); // not ok; reference may be modified
}
void notok2() {
std::shared_ptr<SomeObject> localref = objref; // not ok; objref may be modified
localref->dosomething();
}
Note that simultaneous reads on a shared_ptr is safe, so you can choose to use a read-write lock if it makes sense for your application.
If a object is in use then you should make sure that the destructor of the object is not being called before the use of the object ends. If this is the behavior you have then its a potential problem and it really needs to be fixed.
You should make sure that if one thread is destroying your objects then another thread should not be calling functions on that object or the first thread should wait till second thread completes the function calling.
Yes, even destructors might need critical sections to protect updating some global data which is not related to the class itself.
It's possible that while one thread is waiting for CS in destructor the other is destroying the object and if CS belongs to object it will be destroyed as well. So that's not a good design.
You absolutely, positively need to make sure your object lifetime is less than the consumer threads, or you are in for some serious headaches. Either:
Make the consumers of the object children so it's impossible for them to exist outside of your object, or
use message passing/broker.
If you go the latter route, I highly recommend 0mq http://www.zeromq.org/.
Yes while you are in destructor, the object is already invalidated.
I used Destroy() method that enters critical section and then destroys it self.
Lifetime of object is over before destructor is called?
Yes, it is fine to do that. If a class supports such use, clients don't need to synchronize destruction; i.e. they don't need to make sure that all other methods on the object have finished before invoking the destructor.
I would recommend that clients not assume they can do this unless it is explicitly documented. Clients do have this burden, by default, with standard library objects in particular(ยง17.6.4.10/2).
There are cases where it is fine, though; std::condition_variable's destructor, for example, specifically allows ongoing condition_variable::wait() method invocations when ~condition_variable() starts. It only requires that clients not initiate calls to wait() after ~condition_variable() starts.
It might be cleaner to require that the client synchronize access to the destructor โ and constructor for that matter โ like most of the rest of the standard library does. I would recommend doing that if feasible.
However, there are certain patterns where it might make sense to relieve clients of the burden of fully synchronizing destruction. condition_variable's overall pattern seems like one: consider use of an object that handles possibly long-running requests. The user does the following:
Construct the object
Cause the object to receive requests from other threads.
Cause the object to stop receiving requests: at this point, some outstanding requests might be ongoing, but no new ones can be invoked.
Destroy the object. The destructor will block until all requests are done, otherwise the ongoing requests might have a bad time.
An alternative would be to require that clients do need to synchronize access. You could imagine step 3.5 above where the client calls a shutdown() method on the object that does the blocking, after which it is safe for the client to destroy the object. However, this design has some downsides; it complicates the API and introduces an additional state for the object of shutdown-but-valid.
Consider instead perhaps getting step (3) to block until all requests are done. There are tradeoffs...
Related
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.
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.
With C++ RAII, the dtor gets called when the object goes out of scope. The mechanisms for multithreading always involve passing a callback to be run on a new thread. Thus, I don't think it's possible for an object to be constructed in one thread and destructed in another, since those would have to be different scopes.
Am I right about this? Or are there some cases where an objects ctor and dtor can be called in different threads?
Thus, I don't think it's possible for an object to be constructed in one thread and destructed in another, since those would have to be different scopes.
Am I right about this?
No. These functions can be called completely independent of any threading.
Or are there some cases where an objects ctor and dtor can be called in different threads?
Sure there are cases (just daily bread and butter). Think about a simple producer / consumer model and message instances exchanged between threads through a queue.
The producer thread creates the message instance and pushes it into the queue. The consumer takes it off from the queue and the messages destructor will be called after it was processed.
The mechanisms for multithreading always involve passing a callback to be run on a new thread.
False. There's plenty of cases where you just need another thread to do stuff or manage something in the background but don't care about the status. Additionally, there are other signalling methods besides callbacks (just one example would be conditional variables).
Side note: a callback could be called on any thread, including the thread that you passed the callback to. It all depends on how you design the system. You don't have to make a new thread every time you invoke a callback (although that's one way to do it).
Thus, I don't think it's possible for an object to be constructed in one thread and destructed in another, since those would have to be different scopes.
False. Shared pointers allow pointers to objects to be passed around threads and once all references to the object are removed, then the object is destructed.
An example would be a networking thread that constructs an object to represent some message received from the network. That thread then puts that object on a shared queue and some other processing thread processes that message. Once the processing thread has completed, it can destruct the object and free the resources for other things.
I was wondering what would happen in such a class:
class MyClass
{
private:
std::vector<int> iVector;
void Worker()
{
//Lots of stuff done with iVector
//adding, removing elements, etc.
}
}
Let's say I create a thread (invoked by one of the class member functions) that uses iVector and modifies it. Besides this worker, none of the other member functions of the class reads or modifies this std::vector.
Everything seems fine as worker thread is the only one using iVector.
But what would happen when one instance of the object is destroyed? Even if the object is destroyed after the worker thread is finished, destructor for iVector would be invoked from the main thread. Would this lead to undefined behavior?
Thanks!
Firstly I would suggest running a std::join (or your library equivalent) on the thread in the destructor. This will ensure the thread is properly finished and synchronized before the vector destructor runs. This is important as the vector's lifetime must exceed the thread using it.
The C++11 standard and presumably later ones state in 30.3.1.5:
5: Synchronization: The completion of the thread represented by *this
synchronizes with (1.10) the corresponding successful join() return. [
Note: Operations on *this are not synchronized. โ end note ]
Now we have to examine 1.10 for more detail, first this section states:
3: The value of an object visible to a thread T at a particular point
is the initial value of the object, a value assigned to the object by
T, or a value assigned to the object by another thread, according to
the rules below.
Honestly, this is difficult to parse, it does not specify exactly what kind of synchronization join offers and seems to imply it synchronizes only the thread itself and not data it has accessed. Therefore I would go the safe route and run atomic_thread_fence(memory_order_acquire) after join in the main thread, and atomic_thread_fence(memory_order_release) in the child thread just before it finishes which should guarantee full happens before semantics and no UB.
If an execution thread is using the ivector class member, and another thread destroys the object with this class member, the continued use of the ivector class member results in undefined behavior.
Even if the object is destroyed after the worker thread is finished,
destructor for iVector would be invoked from the main thread. Would
this lead to undefined behavior?
No. As you've described, this situation is not undefined behavior. The C++ standard does not require an object to be destroyed by the same execution thread that created the object. It's fine for one execution thread to grow, resize the vector, then go away or stop using the vector, and then a different execution thread destroy the entire object.
I have a class object whose functions can be called from different threads.
It is possible to get into a situation where Thread1(T1) is calling destructor,
whereas Thread(T2) is executing some other function on the same object.
Let's say T1 is able to call the destructor first, then what happens to the code running in T2?
Will it produce a crash or since the object is already destroyed, the member function will stop running?
Will taking a mutex lock at entry and unlocking at exit of all class functions ensure that there is no crash in any kind of race that will happen between destructor and member functions?
Appreciate your help!
No. Because the logic is flawed. If it is possible at all that T1 is calling the destructor, a mutex will not prevent it from still trying to do that.
There is shared data between T1 and T2 and as such you must make sure that neither will try to call methods on a non-existing shared object.
A mutex alone will not help.
What you'll get is unknown and unpredictable. You're describing a classic multithreading bug / poor design.
An instance should be properly locked before use, and that includes destruction. Once you do that, it's impossible to call a member function on an instance that's being destroyed in another thread.
Locking inside the functions won't help since if 2 separate threads hold references to the same instance and 1 of them causes it to be destroyed, the other thread is holding a bad reference and doesn't know that. A typical solution is to use refcounts, where destruction is at the responsibility of the object itself once no references to it exist. In C++, you'd usually use shared_ptr<> to do this.
I have a class which calls an asynchronous task using std::async in his constructor for loading its content. ( I want the loading of the object done asynchronously )
The code looks like this:
void loadObject(Object* object)
{
// ... load object
}
Object::Object():
{
auto future = std::async(std::launch::async, loadObject, this);
}
I have several instances of these objects getting created and deleted on my main thread, they can get deleted any time, even before their loading has finished.
I'd like to know if it is dangerous to having object getting destroyed when it is still getting handled on another thread. And how can I stop the thread if the object gets destroyed ?
EDIT: The std::future destructor does not block my code with the VS2013's compiler that I am using due to a bug.
As MikeMB already mentioned, your constructor doesn't finish until the load has been completed. Check this question for how to overcome that: Can I use std::async without waiting for the future limitation?
I'd like to know if it is dangerous to having object getting destroyed when it is still getting handled on another thread.
Accessing object's memory after deletion is certainly dangerous, yes. The behaviour will be undefined.
how can I stop the thread if the object gets destroyed ?
What I recommend you to take care of first, is to make sure that the object doesn't get destroyed while it's still being pointed at by something that is going to use it.
One approach is to use a member flag signifying completed load that is updated in the async task and checked in the destructor and synchronize the access with a condition variable. That will allow the destructor to block until the async task is complete.
Once you've managed to prevent the object from being destroyed, you can use another synchronized member flag to signify that the object is being destroyed and skip the loading if it's set. That'll add synchronization overhead but may be worth it if loading is expensive.
Another approach which avoids blocking destructor is to pass a std::shared_ptr to the async task and require all Object instances to be owned by a shared pointer. That limitation may not be very desireably and you'll need to inherit std::enable_shared_from_this to get the shared pointer in the constructor.
There is nothing asynchronous happening in your code, because the constructor blocks until loadObject() returns (The destructor of a future returned by std::async implicitly joins).
If it would not, it would depend on how you have written your code (and especially your destructor), but most probably, your code would incur undefined behavior.
Yes it is dangerous to having object getting destroyed when it is still getting handled on another thread
You can implement a lot of strategies actually depending on requirements and desired behaviour.
I would implement sort of pimpl strategy here, that means that all actual data will be stored in the pointer that your object holds. You will load all the data to the data-pointer-object and store it in the public-object atomically.
Techincally speaking object should be fully constrcuted and ready to use by the time the constrcutor is finished. In your case data-pointer-object will still probably be not ready to use. And you should make your class to handle correctly that state.
So here we go:
class Object
{
std::shared_ptr<Object_data> d;
Object::Object():
d(std::make_shared<Object_data>())
{
some_futures_matser.add_future(std::async(std::launch::async, loadObject, d));
}
}
Then you make atomic flag in your data-object that will signal that loading is complete and object is ready to use.
class Object_data
{
// ...
std::atomic<bool> loaded {false};
};
loadObject(std::shared_ptr<Object_data> d)
{
/// some load code here
d->loaded = true;
}
You have to check if your object is constrcuted every time when you acces it (with thread safe way) through loaded flag