[omniORB] question re: threading

Sai-Lai Lo S.Lo@uk.research.att.com
08 Nov 1999 11:49:51 +0000


>>>>> 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