From: Roger O on 30 Oct 2009 04:28 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 2 Nov 2009 17:12 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 2 Nov 2009 18:17 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 3 Nov 2009 04:10
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 |