On Monday, October 4, 2021 at 9:19:17 AM UTC-7,
al...@flex-logix.com wrote:
> Thanks Bryan,
> >> I'm not sure. I suspect that assuming Threads are required in order to integrate Tcl into a Qt application is misguided. Threads are often used in places that aren't necessary.
> For any GUI application, the event loop is critical, independent of the presence of threads. Integrate the event loop, then just use Tcl as you would any other C function.
> Using threads are inspired not by the need of integration.
> The backend will run long time processing tasks.
> Having such tasks in the thread is the only real option to keep gui responsive.
> The only alternative of periodically from the code process events causing a lot of issues, is not reliable and impossible to implement without putting a ton of calls into unrelated code.
> The thread is a need , not a desire,
> >> I think it's a mistake to call Tcl_Main() from within a Qt program. You have to decide if this is a Qt application or a Tcl application. Choose one, then use the other toolkit as a dependent subsystem. What does this mean? In the case of a Qt application, create a Tcl interpreter, and initialize it according to the needs of your Qt application. This is different from calling Tcl_Main(), because Tcl_Main() basically assumes "ownership" of everything. Once you have the interpreter, you can call Tcl_Eval*() from Qt (i.e., your C++ code) to run Tcl commands, scripts, etc. Also note that there should only be 1 Tcl interpreter running in a thread, and calls to the interp should only be done from the same thread.
> For our application in a regular workflow GUI is an important , but a "secondary" function.
> Users may choose to show it or not from tcl.
> In fact it has to run on Linux without X present and the user may not be able to start gui.
> So it is natural to say that TCL should be the main.
> But if we want to show gui and immediately face the problem: QWidgets have to be in the main thread.
> So if the system is capable of showing gui, we need to put Qt in the main thread.
> Do we want tcl in the same with GUI thread? No, because 90% of the commands are long running.
> >> I think it's a mistake to call Tcl_Main() from within a Qt program.
> Do you see any specific problem?
Ok, so in your case, using Tcl_Main() is appropriate since this is fundamentally a Tcl application with an optional Qt GUI.
I don't see any specific problem so far. The main thread runs Tcl with a command line user interface, and an optional graphical user interface, both can be active at the same time assuming an integrated event loop. The business logic end of the application runs in a separate thread in all cases.
>
> As far as I understand there are only 3 problems to solve:
> 1. Make tcl and Qt run in different threads (done)
> 2. TCL to GUI notifications ( see no problem)
> Backend has a pointer to interface and QObject class implementing it sends signals connected with queued blocking connection.
> So every command calling it will wait for gui to process it.
> 3. Gui to tcl notifications (this is what I try to solve now):
> Gui has to post the text commands to the tcl thread.
> Gui accesses the data to be shown through implemented by the backend interface.
> Access to such data is controlled by the state of the document,
> which every tcl command changing the state should set, but there is no knowledge about tcl in the gui and vice versa.
A workable solution that I can imagine would be:
1) Main thread has a Tcl interp (call it Tcl-0). Tcl-0 manages the command line interface on the terminal.
2) A separate thread is created for the Document operations, where all the hard work is done. In this thread another Tcl interpreter is created (call it Tcl-Doc).
3) Tcl-0 can then communicate with the Document thread using Tcl's thread commands. User commands typed into the terminal would be read by Tcl-0, which, in turn, would pass the operation onto Tcl-Doc and wait for a response.
4) When the Qt GUI is created, Qt signals/slots can be used, or, the Qt code can call Tcl_Eval(Tcl-0, "string command") in the main thread, and in turn, Tcl-0 will forward the operation to Tcl-Doc, if that is required by the operation.
5) Alternatively, Qt can send a signal to the Document thread, to a specially designed object that will take a "string" argument, and turn around and pass the "string" to the Tcl-Doc interpreter via Tcl_Eval().
The bits you have to invent is the set of custom Tcl commands that interface with the document business logic. A subset of these are for direct Qt/Tcl interactions, and the other set are for User command-line interactions. And there's likely some overlap between the two.
There's also no restriction in having a request come through the Tcl command chain, and having the Document logic reply via a Qt signal back to the GUI.
>
> Do you see any pitfalls in such a design?
The pitfall in the solution I outlined above is it will work well with an integrated event loop, otherwise, all the Tcl operations will have to be restricted to non-event based operations, treating Tcl as purely functional sequential code. Any attempt to use any event operations will lead to bad behavior or deadlocks.
> Otherwise why is it a mistake?
My original assumption was that this is a Qt application, i.e., Qt is the overall top controller for the application, so using Tcl_Main() would be inappropriate in this scenario, in my opinion. But my assumption was wrong, sorry.
-Brian
>
> Best regards,
> Alex