Page 1 of 1

C++ object creation and thread safety

Posted: Fri Feb 18, 2005 5:10 am
by durand
I just saw something very interesting and I wanted to tell someone.

I have a class hierarchy: Thread -> Looper -> Window (ancestor to descendant). And the Looper implements the Thread so that it can run itself (waiting on IPC) in a separate context and the main Application can continue. So, if the Looper thread receives an IPC, it can immediately respond to it while the Application is unaware and doing something else.

My instantiation goes like this:

Window() : Looper() : Thread()

And the Thread is set running before Looper() has finished Constructing.

If a context switch occurs before the Looper() constructor is finished, the actual object is still regarded as only a Thread (with a pure virtual run()) method which Looper was supposed to be overriding.

So, when my Thread stub calls (object)->run()), it looks up in the vtable (which is still only set up to be a Thread) and calls run.. the pure virtual function.

Basically, this means that the object must be fully constructed before anything starts using it.

... err ... which actually sounds very obvious now that I think about it.

But anyway...

Re:C++ object creation and thread safety

Posted: Fri Feb 18, 2005 5:29 am
by distantvoices
are you going to instantiate the looper as a blocked thread object and unblock it after each and everything is fine and up?

Re:C++ object creation and thread safety

Posted: Fri Feb 18, 2005 5:38 am
by durand
Yup, I suppose that's the only way to go.

My threads are created in a suspended state and they have to be manually resumed. However, I was trying to be fancy and do away with the need of Start()'ing Windows.

I guess I'll just have to start the Window as well. It just doesn't seem right to have to start a Window.

My code will now change from:

new Window( Rect(50,50,150,150) );

to:

(new Window( Rect(50,50,150,150) ))->Start();

Nothing fancy. But at least I can be 100% sure that the Thread is calling the Window->run() implementation as opposed to the Looper or Thread implementation.

By the way, this is also the reason why you can't call descendent overridden virtual functions in a base constructor.

So, if all of my classes had a Init() virtual function for which they all provided a implementation, then when Looper() called Init(), it would only call Looper::Init() and not the Window::Init() as you would expect. (Because it's not actually a Window object yet.)

Re:C++ object creation and thread safety

Posted: Fri Feb 18, 2005 5:41 am
by Solar
durand wrote: Basically, this means that the object must be fully constructed before anything starts using it.

... err ... which actually sounds very obvious now that I think about it.
;D ;D ;D

That's correct. Neither constructors nor destructors should throw exceptions, since not-quite-constructed and not-quite-destructed objects can't be handled correctly. Throw an exception from a constructor and the object will never get cleaned up. Catching exceptions from a destructor is a tricky thing most people don't know about (or have you ever used [tt]uncaught_exception[/tt]?)

Try to move all "tricky stuff" into plain member functions, and handle constructors / destructors as atomics (i.e., nothing must go wrong).

Re:C++ object creation and thread safety

Posted: Fri Feb 18, 2005 6:53 am
by distantvoices
Hm. I'm starting the looper with an explicit ui_start(bool ab_threaded) call. It's rather associated with the appliction than with the window - because one application can of course different windows...

oh - this scheme of things makes popping up windows (other than dialog boxen) a bit complicated once the application s up and running. Well --> no problem, gonna do some tricks! ;-)