[Python-Dev] PEP needed? Introducing Tcl objects

Martin v. Loewis martin@v.loewis.de
19 Feb 2002 09:43:21 +0100


Tim Peters <tim.one@comcast.net> writes:

> I believe Martin was correct in large part.  The other part is that, without
> a sleep at all, we would have a pure busy loop here, competing for cycles
> non-stop with every process on the box.

Avoiding the wait to be busy is probably the #1 reason for the
sleep. The alternative to avoid a busy wait would be to do
Tcl_DoOneEvent with TCL_ALL_EVENTS, however, once Tcl becomes idle,
this will block, depriving any other thread of the opportunity to
invoke Tcl.

Of Jeff's options, invoking Tcl_SetMaxBlockTime seemed to be most
promising: I want Tcl_DoOneEvent to return after 20ms, to give other
Tcl threads a chance. So I invented the patch

Index: _tkinter.c
===================================================================
RCS file: /cvsroot/python/python/dist/src/Modules/_tkinter.c,v
retrieving revision 1.123
diff -u -r1.123 _tkinter.c
--- _tkinter.c	26 Jan 2002 20:21:50 -0000	1.123
+++ _tkinter.c	19 Feb 2002 08:34:17 -0000
@@ -1676,7 +1967,11 @@
 {
 	int threshold = 0;
 #ifdef WITH_THREAD
+	Tcl_Time blocktime = {0, 20000}; 
 	PyThreadState *tstate = PyThreadState_Get();
+	ENTER_TCL
+	Tcl_SetMaxBlockTime(&blocktime);
+	LEAVE_TCL
 #endif
 
 	if (!PyArg_ParseTuple(args, "|i:mainloop", &threshold))
@@ -1688,16 +1983,15 @@
 	       !errorInCmd)
 	{
 		int result;
+						    
 
 #ifdef WITH_THREAD
 		Py_BEGIN_ALLOW_THREADS
 		PyThread_acquire_lock(tcl_lock, 1);
 		tcl_tstate = tstate;
-		result = Tcl_DoOneEvent(TCL_DONT_WAIT);
+		result = Tcl_DoOneEvent(0);
 		tcl_tstate = NULL;
 		PyThread_release_lock(tcl_lock);
-		if (result == 0)
-			Sleep(20);
 		Py_END_ALLOW_THREADS
 #else
 		result = Tcl_DoOneEvent(0);

However, it does not work. The script

import Tkinter
import thread
import time

c = 0
l = Tkinter.Label(text = str(c))
l.pack()

def doit():
    global c
    while 1:
        c+=1
        l['text']=str(c)
        time.sleep(1)

thread.start_new(doit, ())
l.tk.mainloop()

ought to continously increase the counter in the label (once a
second), but doesn't, atleast not on Linux, using Tcl 8.3.3.  In the
strace output, it appears that it first does a select call with a
timeout, but that is followed by one without time limit before
Tcl_DoOneEvent returns.

Jeff, any ideas as to why this is happening?

Regards,
Martin