Interactive application wrapped with SWIG

Rob McDonald <[email protected]> Thu, 13 Jan 2022 16:20:25 -0800
Newsgroups gmane.comp.programming.swig
Message-ID <CAEppYpGLPzPDwVhAGdevdC6i_VL8OKoU-5PMU_RAGn0vJ1JoaA@mail.gmail.com>
Apologies for the long setup to this question, hopefully someone will bear
with me and will be able to help.

I have a C++ program that has an API wrapped with SWIG.  Users commonly use
SWIG generated Python bindings.

This program is not written to be thread safe.  For all reasonable
purposes, it is a single threaded application.

My program has a GUI (FLTK based) including 3D visualization with OpenGL.
It has been designed such that the core computation engine can be compiled
without the GUI and OpenGL code and all the dependencies.  That version can
be executed on a computer with no graphics libraries or OpenGL drivers
installed.

If the normal version of the application is called 'app_g' (with graphics),
then the no-graphics version might be called 'app_ng'.  Similarly, when I
build the SWIG bindings, I can build '_api_ng.so' and '_api_g.so' versions.

Today, users of the Python bindings use the no-graphics version

import api_ng as foo
foo.bar()
# etc.


The application and API are designed such that nearly all state is stored
on the C++ side of things.  Large and complex objects are not passed back
through the bindings, only relatively simple (and small) data is passed
through the interface.

My understanding is that when Python encounters the 'import' line, it
creates an instance of my program and keeps it active in memory.  It then
lies dormant until it receives a command via 'foo.bar()' or whatever.

Long ago, we also allowed users to import the graphical version of the
bindings along with some added commands...

import api_g as foo
foo.StartGUI()
# etc.

Here, the 'StartGUI()' call would launch the application's GUI and then
start its event loop.  The user could then interact normally with the GUI.
When they were finished, they would close the window.

When the window was closed, we would exit the event loop -- but we would
not terminate the program, exit(), or free memory.  This way, control would
be returned to Python.

In this way, a Python program could use the API, or it could provide an
interactive GUI to the user.  However, it could not do both at once.

I say long ago because we had trouble getting this to work properly on one
platform and we ended up disabling the feature without ever tracing down
the problem.  We've lived happily without it for about a decade.  We
regularly build on Windows, Mac, and Linux as well as some BSD and other
*NIX.  We do not currently build on any phones, tablets, game consoles,
embedded platforms, etc.

Now I have a use case where I want to use the GUI while the API is being
accessed.  However, unlike before, we would like the GUI to be accessible
simultaneously with the Python environment making API calls -- or going on
doing something else.

I think the way to accomplish this goal is to have the call to StartGUI()
launch the event loop in a separate thread.

A single lock is implemented to make access thread safe.  When any GUI
event occurs, the lock is checked out when execution leaves the event
loop.  That event is handled and the lock is released when execution
returns to the event loop.

Similarly, every API call needs to check out and return the lock.  When an
API call is made, it will first check out the lock -- waiting until it is
released by the GUI if needed.  Once it has the lock, it will execute the
desired command, releasing the lock when done.

While this is a very coarse-grained approach to locking, it seems the most
reasonable approach initially.  I believe it will suffice, but it may be
possible to move to a more fine grained locking arrangement sometime later.

Depending on how long the lock is checked out by the API, it might make
sense to add some visual queue to the GUI -- say a red/green box in the
corner indicating whether execution lies with the API or is free for the
user to interact.

Now for the question...

Is this the right approach?  Is there something fundamentally wrong with
this idea?  Can anyone point me at an example application that takes this
approach?

Thanks in advance for any help,

Rob

_______________________________________________
Swig-user mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/swig-user