Passing a "this" pointer to a free thread - c++

I'm looking for a pattern or set of classes to deal with the following:
I have a class that is going to start a "child thread" which is going to run some code, and then make a callback on the class that launched it.
There is a chance that the object that launched the thread, and is awaiting the callback may be destroyed by the time the function returns. I've thought of rolling my own solution where I'd wrap the "this" pointer in a set of classes which would:
Allow the caller to "notify" thread that is going to be using the "this" pointer that it's pointer is no longer valid because it's being destructed.
Allow the "child thread" prevent the destruction of the "this" pointer when its making the callback.
The idea is that I'm looking for a way for a "free" thread (i.e. thread::detach has been called) to make a callback on an object that may have been destructed without throwing an exception.
Basically I have some UI elements that are launching threads, passing callback functions as "continuations". The problem is that the UI elements may be destroyed by the time the new thread is complete.

Related

Can C++ std::thread callable's object pointer be invalidated after the thread begins execution?

I have this chunk of code...
A non-static member method (serving as callable for thread):
void Object::unregister()
{
...
}
and destructor like this:
Object::~Object()
{
std::thread cleanup(&Object::unregister, this);
cleanup.detach();
}
What I see as a problem is that I am running a thread with parameter this which become invalidated when destructor finishes, so I assume it is dangerous, because I do not have any garantee, that the cleanup thread already started - and this my subquestion - is safe if this would be invalidated (destructor finishes) before the call to unregister finishes completely (in other words is it ok, if it already started, but did not finish completely)?
I would say that answer is No as the copy of this pointer is used with callable, but I am not sure as the app behaves, like it does not mind and everything is OK.
If it is ok that thread just started and did not finish yet, is there any way to know that the thread is already running? Would usage of call to joinable() return me true just when the thread is already executing or it can return true before the thread's execution started?
Is there any way how to do it safe and be sure that callable &Object::unregister and this will not be invalidated, because Object was destroyed meanwhile?
is safe if this would be invalidated (destructor finishes) before the call to unregister finishes completely (in other words is it ok, if it already started, but did not finish completely)?
No, it's not safe.
Consider the following C code:
void Object_unregister(void* obj)
{
Object* this = (Object*)obj;
fclose(this->file_handle);
while (this->ref_counter > 0) {
fclose(this->ref_array[this->ref_counter]->handle);
free(this->ref_array[this->ref_counter]);
this->ref_array[this->ref_counter] = NULL;
--this->ref_counter;
}
}
void destroy_Object(Object** this)
{
pthread_t thread;
pthread_create(&thread, NULL, &Object_unregister, (void*)*this);
pthread_detach(&thread);
free(*this);
*this = NULL;
}
This is, at a very basic level, what your C++ code is doing. In this code, we create the thread, then detach it, then immediately free the memory space where the Object was at. In this way, there's no guarantee that the this pointer in the Object_unregister function will point to the same Object that was passed to it.
There is a (general) guarantee that the thread function will still point to the same function pointer address the thread was created with, and that it will run until that function has completed, and in the above code, there is a guarantee that the this pointer will point to the same memory address from when the function was called.
But ...
this could point to 0xABADCAFE and this->file_handle will point to this + sizeof(Object::file_handle), but if you've deleted the object, then what is actually at that address could no longer point to a valid reference of an Object type.
It could point to some random bit of encryption code, or a new function, or just about anything, but it could still point to the object that was originally there if that memory space was not reallocated by the kernel.
So no, it's not safe.
Is there any way how to do it safe and be sure that callable &Object::unregister and this will not be invalidated, because Object was destroyed meanwhile?
Well it depends on what your Object::unregister code actually does in the context of the rest of your code. It's not immediately clear why you want to thread the destructor and you don't just call this->unregister(); in the destructor, example:
Object::~Object()
{
this->unregister();
}
That's as safe as you can get in the context of your code.
But if there's other things that necessarily need to be done in a threaded way, you could do many architectural things to thread the destruction of the object, from static values to locking mechanisms, but essentially what you would need to do is make copies of the specific values you need to unregister so they remain valid in your thread code.

Must an object's ctor and dtor be on the same thread?

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.

Preventing variables from going out of scope so they persist for another thread

I have a function that creates a bunch of local variables, then passes their addresses to a function that runs in a separate thread - something like this:
void MyFunction()
{
MyClass a;
AnotherClass b;
...
FinalClass z;
CallFunctionInNewThread(&a,&b,&c,...,&z);
}
Of course, these variables are destroyed when the MyFunction goes out of scope (so the function in a thread is now pointing to garbage), so this setup doesn't work. What are my options here? If I allocate the variables on the heap with 'new', I will never get a chance to delete them. If I make them smart pointers or similar, I'd have to make the threaded function accept them as smart pointers, or their reference count will not be increased so they will still get destroyed immediately. It seems like they kind of want to be member variables of a wrapper class of MyFunction, but there are a few hundred lines and tens of these things and that would just be crazy messy. Are there any other choices?
Are there any other choices?
Simply copy (if trivial) or move/swap the data (if heavy to create) -- similar to transferring ownership from one thread to the other. Seems Thread A really does not need a reference from the description. Bonus: This removes concurrent access complexities from your program.
One little trick you can do is to pass a semaphore object into the thread function and then wait for that semaphore to be signaled. You do need to check that the thread was created successfully.
The new thread first makes local copies of the values (or references in the case of smart pointers), then signals the semaphore and carries on.
The calling thread can then continue and drop those objects off its stack without interfering with your new thread. It can even delete the semaphore object since it is no longer required by either thread.
It does mean that the calling thread has to wait until the thread is started and has copied its data, but that probably will be a short time. If you are going to the effort of spawning a thread to do any work at all, then this slight delay in the parent thread ought to be acceptable.

How do I pass a pointer to a class object between threads and have it persist after the main thread finishes executing?

Here's the problem that I'm having:
The main thread creates class objects (mybaseclass* local = new childclass;) which are essentially commands that know what they are suppose to do. It then passes a pointer to the class object to a forked thread over a socket and then the main thread is done with the object and returns waiting for some other input. The forked thread then reads the pointer from the queue, but the class object that the pointer was pointing to has already been automatically deleted when the main thread completed. How do I get the class object to persist once the main thread is done executing?
Thanks!
Jeff
Objects allocated on the heap with the new keyword aren't automatically deleted when a thread completes. If you're positive that it's being automatically deleted, you may have a bug elsewhere. Otherwise, the pointer should still point to a valid object.
In your main thread, create your object on the free store, using new:
mybaseclass* local = new childclass;
...being sure not to use a smart pointer, as the smart pointer will destroy the object when it falls out of scope. Pass the pointer to your worker thread via whatever means you are using, then when your worker thread is done with it, delete it:
mybaseclass* thread_local = SomehowGetTheObject();
// MAGIC HAPPENS...
delete thread_local;
Also, if you are passing around base pointers to derived classes, be sure your base class has a virtual destructor.

Is it okay to use "delete this;" on an object that inherits from a Thread class?

In general, if you have a class that inherits from a Thread class, and you want instances of that class to automatically deallocate after they are finished running, is it okay to delete this?
Specific Example:
In my application I have a Timer class with one static method called schedule. Users call it like so:
Timer::schedule((void*)obj, &callbackFunction, 15); // call callbackFunction(obj) in 15 seconds
The schedule method creates a Task object (which is similar in purpose to a Java TimerTask object). The Task class is private to the Timer class and inherits from the Thread class (which is implemented with pthreads). So the schedule method does this:
Task *task = new Task(obj, callback, seconds);
task->start(); // fork a thread, and call the task's run method
The Task constructor saves the arguments for use in the new thread. In the new thread, the task's run method is called, which looks like this:
void Timer::Task::run() {
Thread::sleep(this->seconds);
this->callback(this->obj);
delete this;
}
Note that I can't make the task object a stack allocated object because the new thread needs it. Also, I've made the Task class private to the Timer class to prevent others from using it.
I am particularly worried because deleting the Task object means deleting the underlying Thread object. The only state in the Thread object is a pthread_t variable. Is there any way this could come back to bite me? Keep in mind that I do not use the pthread_t variable after the run method finishes.
I could bypass calling delete this by introducing some sort of state (either through an argument to the Thread::start method or something in the Thread constructor) signifying that the method that is forked to should delete the object that it is calling the run method on. However, the code seems to work as is.
Any thoughts?
I think the 'delete this' is safe, as long as you don't do anything else afterwards in the run() method (because all of the Task's object's member variables, etc, will be freed memory at that point).
I do wonder about your design though... do you really want to be spawning a new thread every time someone schedules a timer callback? That seems rather inefficient to me. You might look into using a thread pool (or even just a single persistent timer thread, which is really just a thread pool of size one), at least as an optimization for later. (or better yet, implement the timer functionality without spawning extra threads at all... if you're using an event loop with a timeout feature (like select() or WaitForMultipleObjects()) it is possible to multiplex an arbitrary number of independent timer events inside a single thread's event loop)
There's nothing particularly horrible about delete this; as long as you assure that:the object is always dynamically allocated, andno member of the object is ever used after it's deleted.
The first of these is the difficult one. There are steps you can take (e.g. making the ctor private) that help, but nearly anything you do can be bypassed if somebody tries hard enough.
That said, you'd probably be better off with some sort of thread pool. It tends to be more efficient and scalable.
Edit: When I talked about being bypassed, I was thinking of code like this:
class HeapOnly {
private:
HeapOnly () {} // Private Constructor.
~HeapOnly () {} // A Private, non-virtual destructor.
public:
static HeapOnly * instance () { return new HeapOnly(); }
void destroy () { delete this; } // Reclaim memory.
};
That's about as good of protection as we can provide, but getting around it is trivial:
int main() {
char buffer[sizeof(HeapOnly)];
HeapOnly *h = reinterpret_cast<HeapOnly *>(buffer);
h->destroy(); // undefined behavior...
return 0;
}
When it's direct like this, this situation's pretty obvious. When it's spread out over a larger system, with (for example) an object factory actually producing the objects, and code somewhere else entirely allocating the memory, etc., it can become much more difficult to track down.
I originally said "there's nothing particularly horrible about delete this;", and I stand by that -- I'm not going back on that and saying it shouldn't be used. I am trying to warn about the kind of problem that can arise with it if other code "Doesn't play well with others."
delete this frees the memory you have explicitly allocated for the thread to use, but what about the resources allocated by the OS or pthreads library, such as the thread's call stack and kernel thread/process structure (if applicable)? If you never call pthread_join() or pthread_detach() and you never set the detachstate, I think you still have a memory leak.
It also depends on how your Thread class is designed to be used. If it calls pthread_join() in its destructor, that's a problem.
If you use pthread_detach() (which your Thread object might already be doing), and you're careful not to dereference this after deleting this, I think this approach should be workable, but others' suggestions to use a longer-lived thread (or thread pool) are well worth considering.
If all you ever do with a Task object is new it, start it, and then delete it, why would you need an object for it anyway? Why not simply implement a function which does what start does (minus object creation and deletion)?