Is it possible to use Intvar / DoubleVar in a Python thread?

Let me just preface this by saying: I will almost certainly use Queue for my program. I am posting this question more or less in order to satisfy my curiosity by spending a decent amount of time studying this topic without finding any definitive answers.

So the question is: is it safe to access / edit IntVar() , DoubleVar() , etc. from anywhere other than the main loop? Also, how to just read the value (via x.get() ) from a separate thread? I know that there is no need to edit / update widgets from separate threads, but I did not find any information about Intvars, etc. Any insight would be appreciated.

Here is a related (but rather old) question that has never been answered:

Python / Tkinter: is Tkinter StringVar thread safe (IntVar etc.)?

+1
source share
1 answer

Based on the comments in the source code for the _tkinter module, it looks like tkinter is actually no less designed to be thread safe if Tcl was built with the --enable-threads option. This is confirmed by a resolved error on the Python tracker ( issue11077 ), which states that tkinter is not thread safe, where it was ultimately that all thread safety problems with tkinter were errors that were fixed in Python 2.7.3 +

Here is what the _tkinter module source says about this:

The Tcl interpreter is valid only in the thread that created it, and all Tk actions must also be performed in this thread. This means that mainloop must be called on the thread that the interpreter created. Calls to commands from other threads are possible; _tkinter will queue an event for the interpreter thread, which will then execute the command and return the result. If the main thread is not in mainloop, and the callers throw an exception; if the main loop is started but does not process events, the command call will be blocked.

So, as long as mainloop is actively working in the main thread of the application, tkinter will automatically schedule the method to run in the main thread, which will make it thread safe. However, most Internet sources, in addition to the actual Tkinter source code and the above error report, indicate that using tkinter with streams is crashing. I'm not quite sure what to believe, although in some small examples I tried, updating the GUI from the stream worked fine.

Now you were wondering if the thread safety rules associated with Tk widgets apply to Variable subclasses. He: Here are some of the implementations of Variable , the parent element of IntVar :

 class Variable: _default = "" _tk = None def __init__(self, master=None, value=None, name=None): """Construct a variable MASTER can be given as master widget. VALUE is an optional value (defaults to "") NAME is an optional Tcl name (defaults to PY_VARnum). If NAME matches an existing variable and VALUE is omitted then the existing value is retained. """ # ...snip... if not master: master = _default_root self._master = master self._tk = master.tk def set(self, value): """Set the variable to VALUE.""" return self._tk.globalsetvar(self._name, value) 

When you set variable, it calls the globalsetvar method of the main widget associated with Variable . The _tk.globalsetvar method _tk.globalsetvar implemented in C and internally calls var_invoke , which internally calls WaitForMainLoop , which will try to schedule the command to execute on the main thread, as described in the quote from the _tkinter source included above.

 static PyObject* var_invoke(EventFunc func, PyObject *selfptr, PyObject *args, int flags) { /* snip */ /* The current thread is not the interpreter thread. Marshal the call to the interpreter thread, then wait for completion. */ if (!WaitForMainloop(self)) return NULL; /* snip */ static PyObject * Tkapp_GlobalSetVar(PyObject *self, PyObject *args) { return var_invoke(SetVar, self, args, TCL_LEAVE_ERR_MSG | TCL_GLOBAL_ONLY); } 

Note that this code path is also used for get operations, so set and get operations are defined by the same rules.

+3
source

Source: https://habr.com/ru/post/973945/


All Articles