UI-Dispatch: document some implementation intricacies
This commit is contained in:
parent
d8c19c7a32
commit
805e6047ba
3 changed files with 65 additions and 14 deletions
|
|
@ -36,6 +36,37 @@
|
|||
** subsystems is not deterministic, this rules out passing references to anything tied to some
|
||||
** subsystem lifecycle. Referring to a static singleton is acceptable though.
|
||||
**
|
||||
** # implementation considerations
|
||||
**
|
||||
** Basically the implementation relies on the [standard mechanism][Gtkmm-tutorial] for multithreaded
|
||||
** UI applications. But on top we use our own [dispatcher queue](\ref lib::CallQueue) to allow passing
|
||||
** arbitrary argument data, based on the argument storage of `std::function`. Which in the end effectively
|
||||
** involves two disjoint thread collaboration mechanisms:
|
||||
** - the caller creates a closure of the operation to be invoked, binding all arguments by value
|
||||
** - this closure is wrapped into a `std::function` instance
|
||||
** - which in turn is added into the dispatcher queue. Depending on the implementation,
|
||||
** this might incur explicit locking
|
||||
** - after successfully enqueuing the closure, the GTK event thread is signalled through
|
||||
** the [Glib-Dispatcher], which actually messages through an OS-pipe (kernel based IO)
|
||||
** - the Dispatcher need to be created within the UI event thread (which is the case, since
|
||||
** all of Lumiera's UI top-level context is created in the thread dedicated to run GTK)
|
||||
** - relying on internal GLib / GIO ``magic'', the dispatcher hooks into the respective GLib
|
||||
** ``main context'' to ensure this signalling is picked up from the event thread, which...
|
||||
** - ...finally leads to invocation of the Dispatcher's signal from within the event loop
|
||||
**
|
||||
** This hybrid approach is rather simple to establish, but creates additional complexities at runtime.
|
||||
** More specifically, we have to pay the penalty of chaining the overhead and the inherent limitations
|
||||
** of two thread signalling mechanisms (in our dispatcher queue and within kernel based IO).
|
||||
** It would be conceivable to implement all of the hand-over mechanism solely within our framework,
|
||||
** yet unfortunately there seems to be no easily accessible and thus ``official'' way to hook into
|
||||
** the event processing, at least without digging deep into GLib internals.
|
||||
**
|
||||
** @note as detailed in the documentation for [Glib-Dispatcher], all instances built within a
|
||||
** given receiver thread (here the UI event loop thread) will _share a single pipe for signalling._
|
||||
** Under heavy load this queue might fill up and block the sender on dispatch.
|
||||
**
|
||||
** [Glib-Dispatcher]: https://developer.gnome.org/glibmm/2.42/classGlib_1_1Dispatcher.html
|
||||
** [GTKmm-tutorial]: https://developer.gnome.org/gtkmm-tutorial/3.12/sec-using-glib-dispatcher.html.en
|
||||
** @see NotificationService
|
||||
** @see CallQueue_test
|
||||
*/
|
||||
|
|
@ -48,22 +79,21 @@
|
|||
#include "lib/call-queue.hpp"
|
||||
|
||||
#include <boost/noncopyable.hpp>
|
||||
//#include <string>
|
||||
#include <utility>
|
||||
|
||||
|
||||
namespace gui {
|
||||
namespace ctrl {
|
||||
|
||||
// using std::string;
|
||||
using std::move;
|
||||
// class GlobalCtx;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Helper to dispatch code blocks into the UI event thread for execution.
|
||||
* Implementation of the actual dispatch is based on `Glib::Dispatcher`
|
||||
* @warning any UiDispatcher instance must be created such as to ensure
|
||||
* it outlives the GTK event loop
|
||||
*/
|
||||
class UiDispatcher
|
||||
: boost::noncopyable
|
||||
|
|
|
|||
|
|
@ -24,9 +24,25 @@
|
|||
** Implementation of notifications and updates within the GUI.
|
||||
** This is the actual service implementation and runs within the GUI plugin.
|
||||
**
|
||||
** @todo 1/2017 actually forward invocations on the UI-Bus
|
||||
** Since GTK is _not threadsafe by design,_ any external invocation passed through
|
||||
** this facade service will be dispatched explicitly into the GTK event loop thread.
|
||||
** The implementation of this dispatch is based upon `Glib::Dispatcher` and thus
|
||||
** requires this service instance to be created from within the thread performing
|
||||
** the GTK event loop. Moreover, to avoid segmentation faults on shutdown, the
|
||||
** lifespan of this service instance must exceed the running of the event loop,
|
||||
** since otherwise the event loop might invoke a lambda bound to the `this`
|
||||
** pointer of a NotificationService already decommissioned. The setup of the
|
||||
** standard Lumiera UI top-level context ensures this is the case, since the
|
||||
** UiManager::performMainLoop() maintains the NotificationService instance
|
||||
** and also performs the blocking `gtk_main()` call. Consequently, any
|
||||
** invocation added from other threads after leaving the GTK main loop
|
||||
** but before closing the GuiNotification facade will just be enqueued,
|
||||
** but then dropped on destruction of the UiDispatcher PImpl.
|
||||
**
|
||||
** @todo 1/2017 find a solution for passing diff messages /////////////////////////////////////////////////TICKET #1066
|
||||
**
|
||||
** @see ui-dispatcher.hpp
|
||||
**
|
||||
*/
|
||||
|
||||
|
||||
|
|
@ -73,7 +89,7 @@ namespace gui {
|
|||
void
|
||||
NotificationService::displayInfo (string const& text)
|
||||
{
|
||||
INFO (gui, "@GUI: display '%s' as notification message.", cStr(text));
|
||||
INFO (gui, "@GUI: display '%s' as notification message.", cStr(text)); ///////////////////////////////////TICKET #1102 : build a message display box in the UI
|
||||
////////////////////////TODO actually push the information to the GUI ///////////////////////////////////TICKET #1098 : use a suitable Dispatcher
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1034,11 +1034,17 @@
|
|||
<node CREATED="1501938690626" ID="ID_353231581" MODIFIED="1501938729247" TEXT="thread safe queue"/>
|
||||
<node CREATED="1501938705321" ID="ID_1924064403" MODIFIED="1501938711076" TEXT="lambdas für Argument-binding"/>
|
||||
</node>
|
||||
<node CREATED="1501938776839" ID="ID_1031878628" MODIFIED="1502371627144" TEXT="Anwendung explizit">
|
||||
<icon BUILTIN="pencil"/>
|
||||
<node CREATED="1501939110138" ID="ID_203135379" MODIFIED="1501939129491" TEXT="Lambda konstruieren"/>
|
||||
<node CREATED="1501939132431" ID="ID_1400757157" MODIFIED="1501939149321" TEXT="Funktion zum Triggern"/>
|
||||
<node CREATED="1501939149837" ID="ID_1733976265" MODIFIED="1501939157472" TEXT="diese an Glib::Dispatcher binden"/>
|
||||
<node COLOR="#338800" CREATED="1501938776839" ID="ID_1031878628" MODIFIED="1502385810866" TEXT="Convenience-Wrapper">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node CREATED="1501939110138" ID="ID_203135379" MODIFIED="1502385815083" TEXT="Lambda konstruieren">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
<node CREATED="1501939132431" ID="ID_1400757157" MODIFIED="1502385817834" TEXT="Funktion zum Triggern">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
<node CREATED="1501939149837" ID="ID_1733976265" MODIFIED="1502385820938" TEXT="diese an Glib::Dispatcher binden">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1501939174506" ID="ID_504999068" MODIFIED="1501939191040" TEXT="in NotificationService integrieren">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
|
|
@ -1048,7 +1054,9 @@
|
|||
<node CREATED="1502375146395" ID="ID_144811928" MODIFIED="1502378036357" TEXT="CallQueue einrichten">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
<node CREATED="1502375120551" ID="ID_1281399419" MODIFIED="1502375131121" TEXT="Glib::Dispatcher verwenden"/>
|
||||
<node CREATED="1502375120551" ID="ID_1281399419" MODIFIED="1502385766022" TEXT="Glib::Dispatcher verwenden">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
<node CREATED="1502375134501" ID="ID_1011463592" MODIFIED="1502375142424" TEXT="Aufrufe in Lamdas verpacken"/>
|
||||
</node>
|
||||
<node CREATED="1502375294344" ID="ID_640199096" MODIFIED="1502375310242" TEXT="Spezialbehandlung für Shutdown">
|
||||
|
|
@ -1073,9 +1081,6 @@
|
|||
</node>
|
||||
<node CREATED="1502375371230" ID="ID_259224346" MODIFIED="1502375379121" TEXT="eigene Dispatcher-Instanz"/>
|
||||
</node>
|
||||
<node CREATED="1501939160907" ID="ID_188350210" MODIFIED="1502371616753" TEXT="Convenience-Wrapper">
|
||||
<icon BUILTIN="help"/>
|
||||
</node>
|
||||
<node CREATED="1501939193031" HGAP="3" ID="ID_1045913810" MODIFIED="1501939200829" TEXT="Test" VSHIFT="20">
|
||||
<icon BUILTIN="pencil"/>
|
||||
<node COLOR="#338800" CREATED="1501939204166" ID="ID_383444966" MODIFIED="1502075950777" TEXT="CallQueue_test">
|
||||
|
|
|
|||
Loading…
Reference in a new issue