6

I have pointer object to singleton class.

Thread 1: Currently executing a member function of the above said object.
Thread 2: Deletes the above object when the object's member function is still being executed by Thread 1.

What happens to Thread 1 where the member function is being executed? Whether the execution will be stopped midway?

Unihedron
  • 10,902
  • 13
  • 62
  • 72
Laks
  • 71
  • 1
  • 3

4 Answers4

4

It is probably undefined behavior, unless you are extra careful.

Deleting the object while your thread accesses it in an unordered (non-synchronized, basically) manner is undefined behavior, even if you get lucky.

Accessing the members of the object (not just running a member: actually accessing a member -- calling a member function, reading a member variable, etc) after you have synchronized with the delete from the main thread is also undefined behavior.

If you carefully synchronize with the main thread, then do not access the member data nor call a different member function after that synchronization, and the main thread deletes the object after that synchronization, then you are perfectly ok.

Almost anything short of that results in undefined behavior.

While undefined behavior can do almost anything, it would be unexpected undefined behavior for this to cause the execution of the code in the member function to suddenly stop just because the object is deleted. More likely you'd get segfaults, memory corruption, or the like. What is worse is that in many cases, things would work "just fine".

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524
2

You will most likely get undefined behavior. Thread 1 can get a seg fault or it may continue merrily on its way if it accesses no member data (and makes no virtual function calls) after the object's deletion. It also depends on what happens to the memory area after deletion. Is it cleared? Is it non-writable/non-readable? It's all highly implementation dependent as well dependent on the data needs of your application in terms of reusing the data area to handle other allocations.

The guidance is to never delete an object until all use of it is complete. There are some exceptions where member functions delete the object they operate on ensuring there is no more member access after the point of deletion. But other than those few cases that actually justify deletion in a member, don't do this.

In the multi-threaded environment you are describing, be absolutely certain to coordinate object lifetime with object use or you may get very difficult to debug (platform dependent and non-deterministic) behavior.

Michael Goldshteyn
  • 71,784
  • 24
  • 131
  • 181
  • 2
    +1 Though I would say it's undefined behavior *iff* member data is accessed after the delete. It's easy to imagine this as a pure race condition, but it might not be. For all we know, there is synchronization between thread1's advancement through the function and thread2's deletion, in which case this behavior is well-defined. – JoshG79 Aug 09 '13 at 14:13
0

Short answer: You shouldn't do this... You need to make sure the object is not being used before deleting it.

In terms of what the C++ standard specifies, it's (probably) undefined behaviour - something unexpected may well happen. The basis for this is that it's undefined behaviour to use any member (function or variable) of an object after the object has been destroyed. Of course, if the member function looks like this:

void foo::func()
{
   for(;;)
   {
     // do nothing here 
   }
}

then it's NOT undefined behaviour, and the thread can be left running indefinitely, without any ill effect, and the behvaiour (I believe) is well defined (it just keeps running).

Certainly thread 1's execution will definitely not stop simply because the object is being deleted. That is, unless the object actually contains a thread object for thread 1 - in which case, the destructor of the thread object may kill the thread.

In practice, if the object is deleted, it's memory is freed, and the memory may well be reused for some other object a small amount of time later. Depending on what the member function is doing, e.g, what parts of the object it's referring to, and how it's using those members, it may cause a crash, or if it does something like x++; (where x is a member variable), it will modify some memory it no longer is the owner of - and that can be quite tricky to debug, because it will appear like something is randomly changing other objects... This is definitely NOT good (and most likely, it will only happen SOMETIMES, making it really hard to spot when it goes wrong).

Nothing good can possibly come out of this.

You MUST make sure the object is not in use in any way to delete it. One way to do that is of course to have the thread object for thread 1, and kill the thread.

Mats Petersson
  • 126,704
  • 14
  • 140
  • 227
  • I'm pretty sure that `struct foo { void SelfDestroy() { delete this; std::cout << "I was deleted!\n"; } }; int main() { foo* f = new foo; f->SelfDestroy(); }` is not undefined behavior, but it has `this` being deleted while a member function is being executed. – Yakk - Adam Nevraumont Aug 09 '13 at 14:23
  • @Yakk But `delete this` isn't the question. The question involved deleting an object in one thread while it is still being used in another. – James Kanze Aug 09 '13 at 14:28
  • Ok, will try to reformulate my answer to cover the case where an object is being destroyed by another thread, where the original thread is running in a loop inside a member function, without mentioning destruction of the object. – Mats Petersson Aug 09 '13 at 14:28
  • @Yakk: I think I've clarified what is undefined behaviour, and that deleting the object itself doesn't result in undefined behaviour - it is the use of any member after the object has been deleted that is UB. – Mats Petersson Aug 09 '13 at 14:32
  • It is actually any *unordered* (relative to the delete) access to member data that is deleted, or any *ordered and after* access to member data, that causes undefined behavior: if you don't have a point of synchronization in the member that coordinates with the deletion of the object, and then doesn't access any member data after that point, you have UB even if you get lucky because the member happened to be at a late enough point of execution. – Yakk - Adam Nevraumont Aug 09 '13 at 14:57
  • @yakk: Why don't you write a better answer, instead of picking up on every single word that may be wrong in mine. The essence is "Don't delete things while they are still in use". The details are highly dependant on exactly what the thread does (we don't know exactly), and the actual compiler implementation, processor archiecture, etc. – Mats Petersson Aug 09 '13 at 15:00
  • @MatsPetersson because your answer was good, and only had a few minor errors? Making a copy/paste of your answer with your errors corrected would be silly, when yours is close to correct. If you prefer, I could just edit your answer so it isn't wrong, would you prefer that? – Yakk - Adam Nevraumont Aug 09 '13 at 15:03
  • @Yakk: If you think a minor edit will make it much better (particularly since we don't actually have much detail, I thought my answer was clear enough, since mentioning the details of "unordered access" and such things presumes that the OP actually understands what that means [or that I write another two paragraphs explaining it]), then feel free. I will first edit in a summary at the top, be there in a few seconds. – Mats Petersson Aug 09 '13 at 15:08
0

Undefined behavior is the right answer. To avoid such things consider using smart pointers, like this: http://www.boost.org/doc/libs/1_54_0/libs/smart_ptr/shared_ptr.htm or this: http://en.cppreference.com/w/cpp/memory/shared_ptr. They have reference counting mechanism that doesn't allow you to delete using object.

  • Would smart pointers ensure when the pointer itself is accessed from different threads? For example , in thread 1 a method is called as uniqueptr->func , while the execution continues, in another thread uniqueptr->reset() is called. Would calling reset on smart pointer wait until func executes? – bahti May 20 '14 at 18:10
  • No, you should provide a mechanism for multithread usage on your own and 'wait util func executes' on your own;). More info about smart ptrs and multiple threads see here: http://stackoverflow.com/questions/14482830/stdshared-ptr-thread-safety – LukeCodeBaker Jun 02 '14 at 13:02