On Tuesday, 30 November 2021 at 07:37:01 UTC sups... wrote:
Thanks for all the help. I usually don't use pointers frequently so I apologize for the dumb mistake.
There was nothing "wrong" with your use of pointers, per se, rather the issue is the asynchronous nature of multi-thread code, and how that interacts with the lifetimes of the various variables passed between the threads.
The key thing is that the callback function passed to the awake() call is not executed at that point in time in the worker thread, but rather is executed "later" in the main thread - and we do not know when. So any variables that are created (in the worker thread) and passed to the callback function need to be created in such a way that they still exist (and have not changed their value) at the (unknown) future time at which the callback actually executes... It's tricky...
In your original example, some of the strings you were using were created in the worker thread, but the worker thread then expired (taking its variables with it...) so that by the time the callback function tried to use these variables later, they did not refer to anything any more, hence the garbage output and other misbehaviours you observed.
This is a common "pain-point" for asynchronous coding, pretty much everybody struggles with this.
The other common alternative is to use a lock / unlock approach - this allows the worker thread to perform (some) operations immediately "now", alleviating the need to preserve the lifetime of the variables, because they no longer need to be accessed asynchronously by another thread. The disadvantage of locks, however, is that they cause threads to block until all the threads involved can synchronize and thus also tend to serialize actions that could/should otherwise be asynchronous.
For things like rendering to the screen, where the process has only one render context, any thread that accesses that context via locks can then end up serialized with the render context, and in the worst cases you no longer have multi-threaded code at all, rather you have a pointlessly complicated single thread, in effect...
With modern multi-core CPUs, asynchronous threads *usually* make more effective use of the available computing resources - but the downside is the potential complexity of managing the lifetimes of shared data. There are many patterns that are intended to help with that...