Boost logo

Boost :

From: Don G (dongryphon_at_[hidden])
Date: 2005-03-24 11:15:29


Hi All,

I've renamed the subject from "Asynchronous I/O" because I wanted to
float the notion that async behavior not be viewed as an aspect of
I/O, though it is highly desired in that space.

Below is a sketch and some pseudo-code of how I've done this over the
past few years, in a portable manner.

The trick to portability for me was integrating into various kinds of
threads or main loops. For example: the main GUI thread of a Windows
application, or a Motif (Xt) based application, or a Mac
application's main event loop. These are the hard ones. Once they are
possible, most (more likely "all") others are possible as well.

Unfortunately, the needs of these integrators is not portable, but
can be hidden behind simple wrapper classes for anticipated cases. To
handle other cases, the integration mechanism needs to be visible. In
the case of the GUI thread integrations, I have a single class to
instantiate, though its details were wildly different for each
platform.

Depending on how this discussion goes, I plan to convert these ideas
into a proposed library.

Best,
Don

------ Sketch --------

1. The user creates one or more "nexus" objects. These objects store
the queue of events, typically one-per-thread. Since some action is
typically required as messages are enqueued, a callback is supplied
to open() which gets called as each message is added.

2. The owner of the nexus is responsible for calling the pump()
method to drain the messages. This method is intended for only one
thread and hence is not internally thread-safe (i.e., BYOM ... Bring
Your Own Mutex).

3. To queue calls, client code needs to create a "channel" object and
connect it with a nexus. The reason for this object is that it is a
proxy for the "ability to still dispatch a message". In other words,
if a receiver object finds itself in its destructor, it will want to
cancel any queued calls to it. Of course, this can be applied
externally to objects, which is why channel is not a base class.

4. Once a channel is open, the async_call() method is used to put a
message in flight. This is thread-safe.

5. Where other code needs a function<>, the channel can be used to
create a shim function<> that accepts N arguments, and binds them
into a queued call.

------ Pseudo-code --------

class nexus
{
 friend class channel;
 public:
    typedef function<void (void)> message;

    // Return true if there is an object associated with
    // the current thread.
    static bool available ();

    // Return the object associated with the current
    // thread. Throw if there is none.
    static nexus & get_current ();

    // Connect this object with the current thread. The
    // ntfy callback is made whenever a message is added
    // to this queue.
    void open (const message & ntfy);

    void close ();

    // Remove a message from the queue. Don't wait any
    // longer than "t". If t == 0 and there is a message
    // in the queue, dispatch it now.
    void pump (const timeout & t = timeout::infinite);

 private:
    struct entry
    {
        channel * ch;
        message msg;
    };
    typedef std::list<entry> messages;

    messages msgs_;
    message ntfy_;

    void enqueue (channel * ch, const message & msg)
    {
        msgs_.push_back(entry(ch, msg));
        ntfy_();
    }

    // Remove all entry's in msgs_ with == channel*.
    void purge (channel * ch);
};

class channel
{
 typedef nexus::message message;
 public:
    void open (nexus * nx = 0)
    {
        if (!nx)
            nx = &nexus::get_current();
        close();
        target_ = nx;
    }

    void close ()
    { target_->purge(this); }

    void async_call (const message & msg)
    { target_->enqueue(this, msg); }

    // Create a callback that calls "this->async_call(msg)".
    message bind_async_call (const message & msg);

    // Create a callback that accepts T and calls
    // "this->async_call(bind(msg, t))".
    template <typename T1>
    function<void (T)>
        bind_async_call (const function<void (T)> & msg);

    // More flavors of bind_async_call()

 private:
    nexus * target_;
};

                
__________________________________
Do you Yahoo!?
Yahoo! Small Business - Try our new resources site!
http://smallbusiness.yahoo.com/resources/


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk