Well, libposif-1.0 is now here, together with my first fully-functioning libposif-1.0-based GUI application. By far the #1 candidate for a host environment is the Qt framework because it's both LGPL-ed and multi-platform, but by no means does a libposif-based application rely on any of the Qt-specific mechanisms (no signal/slot, event loop, etc dependencies whatsoever): in fact, all the fundamental multi-threading and messaging-related mechanisms available in Qt have have a [somewhat equivalent, or more sophisticated] native C++11 implementation in libposif, and all that is required for having a libposif-based application integrated in any host environment, may it be event loop-based or not, is a sequence of three next-to-trivial steps:
- Derive a host environment-specific class from a libposif-defined "MessagingInterface" abstract class - e.g. "MyMessagingInterface": this class is the host environment's messaging interface with the application, and it implements [pre-processing and] relaying of application-defined, environment-agnostic messages sent by back and forth between the libposif application's I/O buffer and the native environment's components (windows/widgets/etc)
- Instantiate a MyMessagingInterface object inside the host environment, e.g. by including it in a GUI application's main window or inside an invisible form, etc
- Cross-link the native environment's objects (i.e. windows, forms, dialogs, etc) with the MyMessagingInterface object (nothing weird or hi-thech here, just some plain old pointer cross-referencing between the host environment's native objects and the MyMessagingInterface object, say 10 minutes of typing some pointer variable declarations and some pointer assignments).
And because a picture's worth a thousand words, here's how a libposif-based application integrates in a host environment...
...and here's a screenshot of my test application, integrated in a Qt-based GUI:
- first of all, it is a proof of concept for an event loop-based environment integration:
- the two "Send to" buttons in the main window actually send a message to the application, and the application sends back the message to the GUI which directs it to the proper window (as specified in the message)
- all the other buttons send messages to the application, which then relays them to the appropriate Automaton for processing
- each counter is implemented as an Automaton in a separate Tread
- each counter Automaton is implemented by having it send a scheduled message targeted to itself, with the schedule specifying that the message is to be actually sent with a specified delay after the SendMessage() method invocation (scheduled messages and targeted messages are examples of features that do not have a Qt equivalent)
- counter 1 in the Main window sends a message
to itself with precisely
one-second delay, thus making the counter increment once/second
- counter 2 in the Main window sends a message to itself with a three second average delay, and with a specified delay dispersion (in %), i.e. the messages will actually be sent with an average, but not precise, 3 second delay (e.g. for a 40% dispersion the successive delays might be e.g. 3, 2, 2, 4, 3, 4... seconds ), which will cause the counter to be incremented on average, but not precisely, every 3 seconds
- the two counters can be started/stopped from their corresponding
Start/Stop buttons: each button sends a message to the application,
which then relays the message to the corresponding counter Automaton
- counter 1 broadcasts a message to all the Automata in the application every time it increments; the libposif method for having an Automaton broadcast a message is BroadcastMessage(), and it is roughly equivalent to Qt's signal()
- the two Reg/Unreg buttons register/un-register a connection between the "tick" messages broadcasted by the counter 1 Automaton and a corresponding "divider Automaton" represented by the yellow counters to the right of said buttons, where each "divider Automaton" is dividing the incoming "tick"s (broadcasted by counter 1) by the number specified in its corresponding drowp-down list (i.e. by 1 and by 2 in the screenshot above); the libposif methods for registering/un-registering an Automaton as a listener to a broadcasting source are AddMessagingRoute(src, dest) / RemoveMessagingRoute(src, dest), and are roughly equivalent to Qt's connect(src, dest) / disconnect(src, dest) methods
- onMessageReceived() is a predefined virtual function of libposif's Automaton abstract class, and it is triggered (by libposif's internals) each time an Automaton object receives a message (i.e. this method has to be implemented by each specific automaton that is derived from libposif's Automaton abstract class)
- SendIntercomMessage() sends a scheduled message to a specified Automaton (which can be - and in the code snippet below is - the sender Automaton itself)
- BroadcastMessage() broadcasts a scheduled message throughout the application environment, and the message will be received by any/all other Automaton objects that have been set up to listen to the sender Automaton (via AddMessagingRoute())
- SendIOMessage() sends a message to the application's Messaging Interface
- State is the Automaton's [integer] state variable: it is a mandatory component
of any automaton, declared in the Automaton base class
Well, all in all it's been a bit long (and occasionally bumpy) a road to reaching this point, but given what i know is needed to implement the P2P OS algorithms, there was simply no way of cutting corners: i needed an asynchronous computing framework to implement autonomous agents that talk to each other, i needed this framework to be exclusively standards-based in order to be truly cross-platform, and i wanted complete control over how my applications will integrate in any host environment in order not to rely on any particular host framework (may it be open-source or not). And libposif-1.0 does just that. So, finally, i'm now ready to start working on P2P OS itself.
It is my intention to release libposif as a stand-alone open-source module, but before doing that i'll have to write at least a brief documentation for its API, and i have no clue when/if i'll find enough energy to do that. Until then, as always, anyone interested just drop me a line.