Discussion:
[omniORB] Integration into a foreign event-loop
Felix Nawothnig
2009-07-16 03:46:55 UTC
Permalink
Hello.

I'm writing a Qt application which implements a dozen of CORBA interfaces,
most of which are simple observer-like interfaces which cause some kind of
GUI update.

Now, as most widget toolkits Qt needs all GUI related calls be done in a
single thread (actually Qt even needs that thread to be the original
main() thread).

Up until now I just kept adding boilerplate code for each CORBA method
which marshals the data into the GUI thread (using Qt signals). Now the
amount of boilerplate code is getting out of hand - and I decided to try
do this properly instead.

I know I can get myself a single-threaded POA and use ORB::work_pending()
and ORB::perform_work(), possibly triggered by a Qt idle timer or
something that - but as I said, I want to do this _properly_ (not doing it
that way has practical reasons too - there is quite some real-time data
coming in via oneway methods and the application will run on a
battery-powered device, so I really don't want to spent lots of cycles
doing busy waiting).

So, this leaves me with two options:

a) Integrate Qt into the omniORB event-loop.

or

b) Integrate omniORB into the Qt event-loop.

The former is not really an option, as the result would be highly
unportable (I'd have to hook the system-dependent message queue) and would
require me to dig deep into Qt code I really don't want to dig into
(although the omniORB-side integration would be simple).

The latter would be rather simple - if there was an
ORB::wait_for_pending_work() method I could call from a non-main thread;
I'd just do that, when it returns I emit a signal to the GUI thread, it
will get dispatched and inside the handler I'd call ORB::perform_work().

Unfortunatly there is no such thing as ORB::wait_for_work().

And as far as I can say there is currently no way to achieve what I'm
trying to do with omniORB - correct me if I'm wrong.

Now, I've looked into corbaOrb.cc and I suppose It'd be easy for me to
hack (I just need to make invoker_signal accessible for me, right?) - but
as there might be a chance for this functionality to end up in the
upstream distribution (I believe my feature request to be reasonable) I
thought I'd first ask for opinions regarding that matter here.

So, what do you think of an omniORB::wait_for_work()?

Cheers,

Felix
Duncan Grisby
2009-07-22 23:23:43 UTC
Permalink
Post by Felix Nawothnig
Now, as most widget toolkits Qt needs all GUI related calls be done in a
single thread (actually Qt even needs that thread to be the original
main() thread).
Does it really? I don't know anything much about Qt, but a quick search
around finds lots of information about multi-threaded programming with
Qt.

[...]
Post by Felix Nawothnig
a) Integrate Qt into the omniORB event-loop.
or
b) Integrate omniORB into the Qt event-loop.
omniORB doesn't have an event loop per se. It always has multiple
threads handling incoming calls and connection attempts. The main thread
POA policy is implemented using thread switching between the thread that
would normally have handled an upcall into the main thread. It is
therefore a lot less efficient than the normal threading policies.
Post by Felix Nawothnig
The latter would be rather simple - if there was an
ORB::wait_for_pending_work() method I could call from a non-main thread;
I'd just do that, when it returns I emit a signal to the GUI thread, it
will get dispatched and inside the handler I'd call ORB::perform_work().
Unfortunatly there is no such thing as ORB::wait_for_work().
And as far as I can say there is currently no way to achieve what I'm
trying to do with omniORB - correct me if I'm wrong.
There's no current way you can do it.

Rather than the wait_for_work function you propose, I think a better
idea is to allow the application to register a function that is called
whenever a main thread task is inserted. i.e. at the point the code
currently does invoker_signal.signal(), it could call an
application-provided function. In your case, that function would send a
signal to the Qt main thread, instructing it to call perform_work.

If you send a clean patch that implements that scheme, I will definitely
consider integrating it in omniORB.

Cheers,

Duncan.
--
-- Duncan Grisby --
-- ***@grisby.org --
-- http://www.grisby.org --
Felix Nawothnig
2009-07-23 00:17:17 UTC
Permalink
Post by Duncan Grisby
Post by Felix Nawothnig
Now, as most widget toolkits Qt needs all GUI related calls be done in a
single thread (actually Qt even needs that thread to be the original
main() thread).
Does it really? I don't know anything much about Qt, but a quick search
around finds lots of information about multi-threaded programming with
Qt.
Yes it does. :-) Although Qt supports multi-threading (and provides a
rather cool concurrency framework) all the widgets are not thread-safe,
and QApplication::exec() must be called from inside the main() thread
(you'll get an assertion failure otherwise).

I suppose this is for performance reasons - same reason Microsoft
decided against coming up with a thread-safe GUI for .NET.

Of course there's a simple way to do multi-threading with Qt - signals
and slots. Similar to .NET where you have to use BeginInvoke to marshal
data into the main thread in Qt you use signals and slots - QObjects are
thread-aware and know in which thread they were created, signaling
checks the received thread and marshals the call into the event-loop if
the threads differ (by default same-thread emits result in just a
function call).

When you're using signals and slots as your inter-process communication
mechanism (which is possible with QtDBus) everything's fine and straight
forward - but an ORB doesn't emit Qt signals, it calls servant methods. :-)

So you have to invent a signal (from the servant) and a slot (into a
dummy object) for each incoming invocation and connect them - this leads
to massive amount of boilerplate code I'd like to avoid.
Post by Duncan Grisby
omniORB doesn't have an event loop per se. It always has multiple
threads handling incoming calls and connection attempts. The main thread
POA policy is implemented using thread switching between the thread that
would normally have handled an upcall into the main thread. It is
therefore a lot less efficient than the normal threading policies.
Yea, I realized that after digging through the code some more.
Efficiency wouldn't be much of an issue in this case, after all it's
about data coming in modifying a GUI.
Post by Duncan Grisby
Rather than the wait_for_work function you propose, I think a better
idea is to allow the application to register a function that is called
whenever a main thread task is inserted. i.e. at the point the code
currently does invoker_signal.signal(), it could call an
application-provided function. In your case, that function would send a
signal to the Qt main thread, instructing it to call perform_work.
Agreed.
Post by Duncan Grisby
If you send a clean patch that implements that scheme, I will definitely
consider integrating it in omniORB.
Alright, I'll give it a try.

Cheers,

Felix
Liang Qi
2009-07-23 20:42:03 UTC
Permalink
Hi, Felix,

Could you try my articles? Not sure whether they are solutions for
your requirements or not.
http://www.qiliang.net/blog/tag/omniorb

The urls for example code are broken, will be fixed by this weekend.

Regards,
Liang
Post by Felix Nawothnig
Hello.
I'm writing a Qt application which implements a dozen of CORBA interfaces,
most of which are simple observer-like interfaces which cause some kind of
GUI update.
Cheers,
Felix
--
http://www.qiliang.net
Liang Qi
2009-07-23 21:03:37 UTC
Permalink
The urls for example code are ok now.
Post by Liang Qi
Hi, Felix,
Could you try my articles? Not sure whether they are solutions for
your requirements or not.
http://www.qiliang.net/blog/tag/omniorb
The urls for example code are broken, will be fixed by this weekend.
Regards,
Liang
--
http://www.qiliang.net
Felix Nawothnig
2009-07-23 22:27:00 UTC
Permalink
Post by Liang Qi
Could you try my articles? Not sure whether they are solutions for
your requirements or not.
http://www.qiliang.net/blog/tag/omniorb
This only works because your server is not a GUI application.

Assume you'd make MainWidget implement another interface in the client,
and have MainWidget::echoThread() become a CORBA method dispatched by
omniORB, instead of a slot dispatched by Qt (well, it could be both).

You could no longer do that editor->setText(text); call inside
MainWidget::hello() - to quote the Qt documentation ("Thread Support in
Qt"):

Although QObject is reentrant, the GUI classes, notably QWidget and all
its subclasses, are not reentrant. They can only be used from the main
thread. As noted earlier, QCoreApplication::exec() must also be called
from that thread.

Felix
Liang Qi
2009-07-24 13:53:35 UTC
Permalink
Not sure which example you are talking about. But you can try the
call_back, at least from guiclient side, you can use signal/slot
between the OmniORBThread and Qt Gui. Then it could also work on
server side.

Regards,
Liang
Post by Felix Nawothnig
Post by Liang Qi
Could you try my articles? Not sure whether they are solutions for
your requirements or not.
http://www.qiliang.net/blog/tag/omniorb
This only works because your server is not a GUI application.
Assume you'd make MainWidget implement another interface in the client, and
have MainWidget::echoThread() become a CORBA method dispatched by omniORB,
instead of a slot dispatched by Qt (well, it could be both).
You could no longer do that editor->setText(text); call inside
MainWidget::hello() - to quote the Qt documentation ("Thread Support in
Although QObject is reentrant, the GUI classes, notably QWidget and all its
subclasses, are not reentrant. They can only be used from the main thread.
As noted earlier, QCoreApplication::exec() must also be called from that
thread.
Felix
--
http://www.qiliang.net
Loading...