From: Roger O on
On Oct 29, 5:20 pm, David Gravereaux <davyg...(a)pobox.com> wrote:
> Roger,
>
> I wrote some stuff a long time ago about this

Interesting reading. I will have to see how I can apply this to my
situation. Part of my solution involves a socket on which Tcl script
commands can be written. When a thread gets the mutex protecting the
socket, it can write it's script.

My application is fully event driven. If there are no events, there is
nothing to do. The main loop (before Tcl/Tk was added) was:

while (needed) {
DoSomeWork();
pause();
}

So, if events stopped, the program did nothing. This worked perfect,
as all the sockets, serial ports, firewire, keyboard, what-have-you,
use asynchronous notification (or, more recently, are in a thread). I
then added Tcl. The loop became:

while (needed) {
DoSomeWork();
Tcl_DoOneEvent();
}

As you noted in your paper, this results in a polling by Tcl all the
time. It works, but it ain't pretty.

In this setup, DoSomeWork() sets many Tcl variables (via the C API),
based on the state of things as a result of all the async callbacks
and other thread activity. Then, Tcl_DoOneEvent() does all the stuff
needed for things like updating the GUI with the changes in these
variables and running Tcl/Tk scripts. All in one thread.

Part of the solution above involves a socket on which Tcl script
commands can be written. When a thread gets the mutex protecting the
socket, it can write it's script. The socket is only read and executed
in the thread with the main interpreter. This is similar to your FIFO.

One of the biggest issues is with user interaction. To make that work,
I needed the loop as above, since Tk does not do key presses and such
asynchronously in the C API context. I posted a question here a while
back on how to get X events to cause asynchronous events that I could
use to cause calls to Tcl_DoOneEvent. I never got that sorted. I think
it was the wrong approach. Of all the events going on in the system,
key presses are the ones that need to be the most responsive. That is
something that has remained an issue. The key presses are ones that do
not have anything to do with the Tcl/Tk part of the app. They are to
initiate commands to various sub-systems.

So, thanks for the info on Tcl_AsyncMark and friends. I will have to
play with that. OTOH, I can arrange that the Tcl/Tk libraries are
compiled with thread support. So I wonder if that has any
advantages...

--
Roger Oberholtzer


From: David Gravereaux on
Roger O wrote:
...
> So, thanks for the info on Tcl_AsyncMark and friends. I will have to
> play with that. OTOH, I can arrange that the Tcl/Tk libraries are
> compiled with thread support. So I wonder if that has any
> advantages...

Glad that helped.

With thread support compiled in, you can skip Tcl_AsyncMark and go right
to Tcl_QueueThreadEvent. That won't let Tk be alertable to the
keyboard, though. Alertable to the keyboard is allowing Tcl to idle in
Tcl_WaitForEvent. And about the only way to do that is to run Tcl in a
separate thread so it won't collide with your main event loop.

Or maybe replace your custom loop so that Tcl's event loop becomes the
main loop you use and the rest of your app uses Tcl's services through
Tcl_QueueEvent. That's less threading. The magic then becomes doing
execution in a Tcl manner. You probably don't need to move your work to
a fancy channel driver or anything.

int main (int argc, char *argv[]) {
Tcl_FindExecutable(argv[0]);
Init();
while (!exiting) {
Tcl_DoOneEvent(TCL_ALL_EVENTS);
}
Tcl_Finalize();
return 0;
}

--


From: David Gravereaux on
Roger O wrote:
...
> So, thanks for the info on Tcl_AsyncMark and friends. I will have to
> play with that. OTOH, I can arrange that the Tcl/Tk libraries are
> compiled with thread support. So I wonder if that has any
> advantages...

Glad that helped.

With thread support compiled in, you can skip Tcl_AsyncMark and go right
to Tcl_QueueThreadEvent. That won't let Tk be alertable to the
keyboard, though. Alertable to the keyboard is allowing Tcl to idle in
Tcl_WaitForEvent. And about the only way to do that is to run Tcl in a
separate thread so it won't collide with your main event loop.

Or maybe replace your custom loop so that Tcl's event loop becomes the
main loop you use and the rest of your app uses Tcl's services through
Tcl_QueueEvent. That's less threading. The magic then becomes doing
execution in a Tcl manner. You probably don't need to move your work to
a fancy channel driver or anything.

int main (int argc, char *argv[]) {
Tcl_FindExecutable(argv[0]);
Init();
while (!exiting) {
Tcl_DoOneEvent(TCL_ALL_EVENTS);
}
Tcl_Finalize();
return 0;
}

--


From: Roger O on
On Nov 3, 12:17 am, David Gravereaux <davyg...(a)pobox.com> wrote:
> Roger O wrote:
>
> ...
>
> > So, thanks for the info on Tcl_AsyncMark and friends. I will have to
> > play with that. OTOH, I can arrange that the Tcl/Tk libraries are
> > compiled with thread support. So I wonder if that has any
> > advantages...
>
> Glad that helped.
>
> With thread support compiled in, you can skip Tcl_AsyncMark and go right
> to Tcl_QueueThreadEvent.  That won't let Tk be alertable to the
> keyboard, though.  Alertable to the keyboard is allowing Tcl to idle in
> Tcl_WaitForEvent.  And about the only way to do that is to run Tcl in a
> separate thread so it won't collide with your main event loop.
>
> Or maybe replace your custom loop so that Tcl's event loop becomes the
> main loop you use and the rest of your app uses Tcl's services through
> Tcl_QueueEvent.  

I seem to recall a similar suggestion back when I first brought this
up on the list. I do not see that solution happening. I will look at
the threaded Tcl stuff and try to improve the general tcl event loop
integration. And somehow live with the keyboard. It is, in fact, the
biggest problem in our use of Tk. Of course, it is not unique to Tk.
It is a general GUI vs. app issue when the keyboard is doing double
duty as a way to interact with the GUI, as well as control other non-
GUI aspects of the application.

--
Roger Oberholtzer