After thinking and reading the manuals for Xforms, this is the current
idea for asynchronous messaging.

I'm creating three classes, Messenger, Messenger_pimpl and MessengerBoy.

Messenger defines the generic api and will be implemented in
src/frontends (suggested header file attached for comments).
Messenger is using standard signal/slot mechanism to deliver the
messages.

Messenger_pimpl is the actual receive message part and upon message
receipt it turns to messenger (either by pointer or friendness) to
deliver the message.

MessengerBoy does the send message part.

The idea for now is to use a pipe, where Messenger_pimpl has one end,
and the MessengerBoy's have the other end. Access to the pipe will be
protected by a mutex to avoid concurent access by many MessengerBoy's.

pthread is already a requirement so I add nothing to requirements,
waiting on a pipe is done by Xforms without wasting CPU (too much) and
so I dont add any unwanted CPU usage (no busy loop).

The design criterion is to minimize concurrency problems and to allow
mostly everything to run inside the main loop and thus the main thread.

This is a rough sketch, I may go with a scheme that has a pipe for every
signal, it will at least remove the need for mutex but will cost in
extra file handles used (2 for each pipe).

The attached file is my suggestion for Messenger, it might not even
compile yet, but its the current sketch.

-- 
Baruch Even
http://baruch.ev-en.org/
// Messenger is used to send messages asynchronously.
#ifndef MESSENGER_H
#define MESSENGER_H

#include <map>
#include <sigc++/signal_system.h>

#include "LString.h"
#include <boost/utility.hpp>

#ifdef SIGC_CXX_NAMESPACES
using SigC::Signal0;
using SigC::Signal1;
#endif

/** Messenger is used to send messages asynchronously.
 *  The idea is to create a signal/slot that can be emitted from an
 *  asynchronous process and to have the signal emitted from the main
 *  loop of LyX.
 *
 *  The reasoning is that it is better to reduce the amount of work done
 *  in different processes/threads as this reduce the problems associated
 *  with locking access to variables and various other thread safety troubles.
 *
 *  There are two signal types, named and temporary. The named signals can
 *  be used for ongoing and repeated signals, while the temporary signals are
 *  for one-shot signals like the completion of some external task.
 *
 *  When you use a signal you get two things, one is SignalType, this is
 *  the part that gets your signals back to you, that is the main loop part
 *  that you connect to like a regular Signal/Slot mechanism. You also get
 *  a MessengerBoy object that you give the asynchronous task, the messenger
 *  boy is used to send the messages that will trigger the signal.
 */
class Messenger : public noncopyable {
        // This can be used to easily change the message types:
        // MessageType is the type itself i.e. string
        // MessageTypeArg is the argument to functions i.e. string const &
        typedef int MessageType;
        typedef int MessageTypeArg;
        
        /// The signal we provide returns nothing and gets one integer argument.
        typedef Signal1<void, MessageType> SignalType;

        ///
        Messenger();
        ///
        ~Messenger();

        /** This method creates a signal that corresponds to the name given.
         *  If the signal already exists, the existing signal will be returned.
         *  This signal will stay until it is removed, as opposed to temp signals.
         *
         *  Signal names that start with underscore are used for temporary
         *  signals and should not be used otherwise.
         */
        pair<SignalType, MessengerBoy> createNamedSignal(string const & name);
        
        /** This removes the named signal. Returns false if it wasn't there
         *  already.
         */
        bool removeNamedSignal(string const & name);

        /** This returns the signal if it exists at all.
         *  the boolean will be true if the signal has any meaning,
         *  if the boolean is true the signal is meaningless as it is not
         *  connected anywhere.
         */
        pair<bool, pair<SignalType, MessengerBoy> > getNamedSignal(string const & 
name);

        /** This method creates a single use signal, it exits only until it is
         *  fired, and upon firing it is removed.
         *  The idea is for one-shot needs like when an external task is
         *  completed.
         */
        pair<SignalType, MessengerBoy> createTempSignal();

private:
        /** This is used by the Messenger_pimpl to emit the signal when it is
         *  received.
         */
        void emitSignal(string const & name, MessageTypeArg message);
        
        /** This holds the actual implementation of the messaging send and receive
         *  it is platform and toolkit dependent.
         */
        Messenger_pimpl pimpl_;
        friend Messenger_pimpl;
};

#endif

Reply via email to