Matplotlib crashes python without rising any exceptions (python simply closes), when draw method is called on FigureCanvasTkAgg object in threaded application from thread other than main thread.
When button from example shown above is clicked, application window freezes for a moment and than closes along with python, no exception or error is displayed.
Expected outcome
Preferably draw method should run normally, or at least an exception should be rised.
In Matplotlib 2.2.2 same code snipped runs flawlessly.
Matplotlib makes no guarantees of thread safety. You'll need to use other methods to ensure that only one thread accesses it (conditions, mutexes, GUI-specific signals (if available), etc.)
19:59 $ python -X faulthandler /tmp/tk_thread.py
Fatal Python error: Segmentation fault
Current thread 0x00007f7029ab2700 (most recent call first):
File "/home/tcaswell/mc3/envs/dd36/lib/python3.6/site-packages/matplotlib/backends/_backend_tk.py", line 91 in blit
File "/home/tcaswell/mc3/envs/dd36/lib/python3.6/site-packages/matplotlib/backends/backend_tkagg.py", line 10 in draw
File "/home/tcaswell/mc3/envs/dd36/lib/python3.6/threading.py", line 864 in run
File "/home/tcaswell/mc3/envs/dd36/lib/python3.6/threading.py", line 916 in _bootstrap_inner
File "/home/tcaswell/mc3/envs/dd36/lib/python3.6/threading.py", line 884 in _bootstrap
Thread 0x00007f7040fff740 (most recent call first):
File "/home/tcaswell/mc3/envs/dd36/lib/python3.6/tkinter/__init__.py", line 1277 in mainloop
File "/tmp/tk_thread.py", line 15 in <module>
Segmentation fault (core dumped)
Even though we do not claim that Matplotlib is threadsafe, there is no obvious race here and the sefault is coming from inside
Looking upstream at this comment, there does appear to be some queuing involved and using the interpreter across threads is risky. Our _tkagg C code probably does not do that queuing.
Also according to a later comment, Tk may or may not be compiled with thread support.
each interpreter is tightly bound to its OS thread and errors will occur if you let more than one thread call into the same interpreter (e.g., with Tcl_Eval).
We could start peppering the codebase with if threading.current_thread() == threading.main_thread() (in this specific case I guess in _backend_tk.blit, but I'm not sure it's so cheap? And we are explicitly not threadsafe anyways (there are other places which I know have race conditions, e.g. likely most things involving _setattr_cm).
So I'll close as wontfix, but as usual feel free to disagree and reopen...
@xzores Is that thread the main thread? In general GUI toolkits do not like having any part of them be run in a background thread (unless they manage it).
I can't do "if threading.current_thread() == threading.main_thread()", because the main thread is used for tk.mainloop().
So I will never call matlablib from the main thread.
I just want to update a plot. The only way I found is to remove the plot entirely and then remake it, but that is not optimal, for many reasons
and I agree with the "can't fix" label, getting into thread safetly is starting to get into application logic and I suspect that any attempts on our part would invariably conflict with user's attempts to do the same in their application.
I've actually been working on this for some time. Since everyone seems to be looking at this right now, I've made a PR (#18565) to discuss.
In short, we can use the tkinter cross-thread signaling to make draw and blit thread "safe" but Tk_photoputblock is fundamentally not parallelizable, so this only really prevents crashes.
Activity
QuLogic commented on Jan 27, 2019
Matplotlib makes no guarantees of thread safety. You'll need to use other methods to ensure that only one thread accesses it (conditions, mutexes, GUI-specific signals (if available), etc.)
tacaswell commented on Jan 28, 2019
Even though we do not claim that Matplotlib is threadsafe, there is no obvious race here and the sefault is coming from inside
matplotlib/src/_tkagg.cpp
Lines 212 to 250 in 5a53f5e
We may also be hitting non-thread safe operations in tk?
QuLogic commented on Jan 28, 2019
You can get a backtrace via catchsegv python ../mpl-tests/issue13293.py:
Looking upstream at this comment, there does appear to be some queuing involved and using the interpreter across threads is risky. Our _tkagg C code probably does not do that queuing.
Also according to a later comment, Tk may or may not be compiled with thread support.
xzores commented on Sep 24, 2020
I also have this problem, calling everything from the same thread.
Newest matlablib and python, really tiered of it
anntzer commented on Sep 24, 2020
AFAICT this is simply not supported by Tcl. Per http://www.tcl.tk/doc/howto/thread_model.html:
We could start peppering the codebase with if threading.current_thread() == threading.main_thread() (in this specific case I guess in _backend_tk.blit, but I'm not sure it's so cheap? And we are explicitly not threadsafe anyways (there are other places which I know have race conditions, e.g. likely most things involving _setattr_cm).
So I'll close as wontfix, but as usual feel free to disagree and reopen...
tacaswell commented on Sep 24, 2020
@xzores Is that thread the main thread? In general GUI toolkits do not like having any part of them be run in a background thread (unless they manage it).
xzores commented on Sep 24, 2020
No it is in an other thread, but it is the same thread
xzores commented on Sep 24, 2020
I can't do "if threading.current_thread() == threading.main_thread()", because the main thread is used for tk.mainloop().
So I will never call matlablib from the main thread.
I just want to update a plot. The only way I found is to remove the plot entirely and then remake it, but that is not optimal, for many reasons
tacaswell commented on Sep 24, 2020
and I agree with the "can't fix" label, getting into thread safetly is starting to get into application logic and I suspect that any attempts on our part would invariably conflict with user's attempts to do the same in their application.
tacaswell commented on Sep 24, 2020
Use Tk's signaling system to ask the main thread to schedule a draw.
[edit to fix spelling]
xzores commented on Sep 24, 2020
I get some data from the network, that I need to append to the existing data and update the plot
xzores commented on Sep 24, 2020
Calling figure.canvas.draw() crashes my app, no exceptions thrown (that must be a bug)
richardsheridan commented on Sep 24, 2020
I've actually been working on this for some time. Since everyone seems to be looking at this right now, I've made a PR (#18565) to discuss.
In short, we can use the tkinter cross-thread signaling to make draw and blit thread "safe" but Tk_photoputblock is fundamentally not parallelizable, so this only really prevents crashes.