[omniORB] question re: threading
Steven W. Brenneis
brennes1@rjrt.com
Mon, 08 Nov 1999 07:55:29 -0500
With respect to MFC, Microsoft enforces the single-thread-per-window GUI
handling paradigm via assertions. For example, calling
CWnd::DestroyWindow() from a thread which is not the window's message
pumping thread will result in an assertion failure (in debug only,
release code will either do nothing or terminate the application). In
order to perform window functions from a distributed object's dispatcher
thread, it is necessry to invoke CWnd::PostMessage or the WIN32 API
version (::PostMessage). If certain functions are desired from within
the distributed object's thread which are not defined by one or more
WIN32 messages, the best method is to use user-defined messages, or the
registered callback (as Sai-Lai describes), or a combination of both.
Sai-Lai Lo wrote:
>
> >>>>> Matt Goodall writes:
>
> >> If you use omniORB 3 (available via CVS and snapshots) you will be able to
> >> have single-threaded object implementations or multi-threaded ones, as
> >> described in the POA specification.
>
> > Does this mean that it will be easier/possible to use omniORB with
> > single-threaded event driven systems such as X11 and GTK (or MFC for
> > that matter)?
>
> Whether it is TK, GTK or MFC, I think it is a good idea to have just one
> thread, usually the main thread, to interact with the GUI. This thread
> calls into the GUI's event loop and blocks there. Before it does, it
> creates a pipe and registers a callback on this pipe with the GUI. When
> other threads, such as a server thread calling into your CORBA object
> implementation wants to update the GUI, it deposits the GUI command onto a
> queue and kick the GUI thread into calling the callback function by writing
> to the pipe.
>
> The following is some code that I've written for interacting with GTK
> (GTK-- actually). It is not a complete example but I hope you get the idea.
> When a server thread wants to execute a bit of GUI code, it creates a
> command object (derived from frameGUICommand) and call
> gtkMTGUI::pushCommand(). The execute() method of the command object
> contains all the code you want the GUI to execute.
>
> Sai-Lai
>
> ------------------------------------
> class frameGUICommand {
> public:
> virtual ~frameGUICommand() {}
> virtual void execute() = 0;
> protected:
> frameGUICommand() {}
> };
>
> class gtkMTGUI;
>
> static gtkMTGUI* singleton_ = 0;
>
> static omni_mutex globallock;
>
> extern "C" {
> void gtkMTGUI_commandHandler(gpointer data, gint source,
> GdkInputCondition condition);
> }
>
> class gtkMTGUI : public frameMTGUI {
> public:
>
> void run() {
> main_.run();
> }
>
> void pushCommand(frameGUICommand* cmd);
>
> static gtkMTGUI* instance(int& argc, char**& argv) {
> if (!singleton_) {
> singleton_ = new gtkMTGUI(argc,argv);
> }
> return singleton_;
> }
>
> void executeCommands();
>
> private:
> gtkMTGUI(int& argc, char**& argv);
>
> Gtk_Main main_;
> int commandPipe_[2];
> deque<frameGUICommand*> commandQueue_;
> gtkMTGUI();
> };
>
> gtkMTGUI::gtkMTGUI(int& argc, char**& argv) : main_(&argc,&argv) {
> if (::pipe(commandPipe_) == 0) {
> gdk_input_add(commandPipe_[0],GDK_INPUT_READ,
> gtkMTGUI_commandHandler,this);
> }
> else {
> cerr << "Error: gtkMTGUI ctor cannot create a unix pipe. It is therefore not possible to use pushCommand from threads." << endl;
> commandPipe_[0] = commandPipe_[1] = -1;
> }
> }
>
> void
> gtkMTGUI::pushCommand(frameGUICommand* cmd)
> {
> omni_mutex_lock sync(globallock);
>
> if (commandPipe_[1] >= 0) {
>
> if (commandQueue_.empty()) {
> // attract the attention of the GUI thread by write a byte to the
> // commandpipe. Only do so if the command queue is prevously empty.
> char dummy;
> write(commandPipe_[1],(void*)&dummy,1);
> }
>
> commandQueue_.push_back(cmd);
> }
> else {
> cerr << "Error: gtkMTGUI::pushCommand cannot enqueue command." << endl;
> delete cmd;
> }
> }
>
> void
> gtkMTGUI::executeCommands()
> {
> omni_mutex_lock sync(globallock);
>
> deque<frameGUICommand*>::iterator i;
> for (i=commandQueue_.begin(); i != commandQueue_.end(); ++i) {
> (*i)->execute();
> delete (*i);
> }
> if (!commandQueue_.empty()) {
> commandQueue_.erase(commandQueue_.begin(),commandQueue_.end());
> // There would be a byte in the commandpipe, read it
> char dummy;
> read(commandPipe_[0],(void*)&dummy,1);
> }
> }
>
> extern "C"
> void gtkMTGUI_commandHandler(gpointer g,gint,GdkInputCondition)
> {
> ((gtkMTGUI*)g)->executeCommands();
> }
>
> frameMTGUI*
> gtkmtgui_init(int& argc, char**& argv)
> {
> return gtkMTGUI::instance(argc,argv);
> }
>
> ----------------------------------------------------------
>
> --
> Sai-Lai Lo S.Lo@uk.research.att.com
> AT&T Laboratories Cambridge WWW: http://www.uk.research.att.com
> 24a Trumpington Street Tel: +44 1223 343000
> Cambridge CB2 1QA Fax: +44 1223 313542
> ENGLAND