Repository: napari/napari

Issue:
Bug: Segfaults appearing with "QObject::setParent: Cannot set parent, new parent is in a different thread"
## 🐛 Bug

In the last couple days, I've seen this segfault a couple times on main.  I'm not quite sure what's causing it yet, but it tends to happen with mouse movements, perhaps on the canvas, maybe on sliders, not sure...  but it crashes napari out to the console


```
WARNING: QObject::setParent: Cannot set parent, new parent is in a different thread
10:19:54 WARNING QObject::setParent: Cannot set parent, new parent is in a different thread
WARNING: QObject::setParent: Cannot set parent, new parent is in a different thread
10:19:54 WARNING QObject::setParent: Cannot set parent, new parent is in a different thread
WARNING: QObject::setParent: Cannot set parent, new parent is in a different thread
10:19:54 WARNING QObject::setParent: Cannot set parent, new parent is in a different thread
[1]    19897 segmentation fault  napari
```


Discussion:
I also meet this and I notice that every mouse move spawn a new thread. 

I was able to reproduce it under GDB:
```
Thread 1 "python" received signal SIGSEGV, Segmentation fault.
0x00007fff8489d7c0 in QPropertyAnimation::targetObject() const () from /home/czaki/.pyenv/versions/3.8.3/envs/napari/lib/python3.8/site-packages/PyQt5/Qt5/lib/libQt5Core.so.5
(gdb) bt
#0  0x00007fff8489d7c0 in QPropertyAnimation::targetObject() const ()
    at /home/czaki/.pyenv/versions/3.8.3/envs/napari/lib/python3.8/site-packages/PyQt5/Qt5/lib/libQt5Core.so.5
#1  0x00007fff6124e280 in QWidgetAnimator::animationFinished() ()
    at /home/czaki/.pyenv/versions/3.8.3/envs/napari/lib/python3.8/site-packages/PyQt5/Qt5/lib/libQt5Widgets.so.5
#2  0x00007fff84accda3 in QObject::event(QEvent*) ()
    at /home/czaki/.pyenv/versions/3.8.3/envs/napari/lib/python3.8/site-packages/PyQt5/Qt5/lib/libQt5Core.so.5
#3  0x00007fff6116343c in QApplicationPrivate::notify_helper(QObject*, QEvent*) ()
    at /home/czaki/.pyenv/versions/3.8.3/envs/napari/lib/python3.8/site-packages/PyQt5/Qt5/lib/libQt5Widgets.so.5
#4  0x00007fff61169f20 in QApplication::notify(QObject*, QEvent*) ()
    at /home/czaki/.pyenv/versions/3.8.3/envs/napari/lib/python3.8/site-packages/PyQt5/Qt5/lib/libQt5Widgets.so.5
#5  0x00007fff61c6bcd6 in sipQApplication::notify(QObject*, QEvent*) ()
    at /home/czaki/.pyenv/versions/3.8.3/envs/napari/lib/python3.8/site-packages/PyQt5/QtWidgets.abi3.so
#6  0x00007fff84a9d808 in QCoreApplication::notifyInternal2(QObject*, QEvent*) ()
    at /home/czaki/.pyenv/versions/3.8.3/envs/napari/lib/python3.8/site-packages/PyQt5/Qt5/lib/libQt5Core.so.5
#7  0x00007fff84aa0882 in QCoreApplicationPrivate::sendPostedEvents(QObject*, int, QThreadData*) ()
--Type <RET> for more, q to quit, c to continue without paging--
    at /home/czaki/.pyenv/versions/3.8.3/envs/napari/lib/python3.8/site-packages/PyQt5/Qt5/lib/libQt5Core.so.5
#8  0x00007fff84af9b33 in postEventSourceDispatch(_GSource*, int (*)(void*), void*) ()
    at /home/czaki/.pyenv/versions/3.8.3/envs/napari/lib/python3.8/site-packages/PyQt5/Qt5/lib/libQt5Core.so.5
#9  0x00007fffe9919d1b in g_main_context_dispatch ()
    at /lib/x86_64-linux-gnu/libglib-2.0.so.0
#10 0x00007fffe996e6f8 in  () at /lib/x86_64-linux-gnu/libglib-2.0.so.0
#11 0x00007fffe99173c3 in g_main_context_iteration ()
    at /lib/x86_64-linux-gnu/libglib-2.0.so.0
#12 0x00007fff84af91cc in QEventDispatcherGlib::processEvents(QFlags<QEventLoop::ProcessEventsFlag>) ()
    at /home/czaki/.pyenv/versions/3.8.3/envs/napari/lib/python3.8/site-packages/PyQt5/Qt5/lib/libQt5Core.so.5
#13 0x00007fff84a9c21a in QEventLoop::exec(QFlags<QEventLoop::ProcessEventsFlag>) ()
    at /home/czaki/.pyenv/versions/3.8.3/envs/napari/lib/python3.8/site-packages/PyQt5/Qt5/lib/libQt5Core.so.5
#14 0x00007fff84aa51d3 in QCoreApplication::exec() ()
    at /home/czaki/.pyenv/versions/3.8.3/envs/napari/lib/python3.8/site-packages/PyQt5/Qt5/lib/libQt5Core.so.5
#15 0x00007fff61ab64c1 in meth_QApplication_exec_ ()
    at /home/czaki/.pyenv/versions/3.8.3/envs/napari/lib/python3.8/site-packages/PyQt5/QtWidgets.abi3.so
--Type <RET> for more, q to quit, c to continue without paging--
#16 0x00007ffff7ccea27 in cfunction_call_varargs
     (func=<built-in method exec_ of QApplication object at remote 0x7fff8730fee0>, args=<optimized out>, kwargs=<optimized out>) at Objects/call.c:757
#17 0x00007ffff7ccf12b in _PyObject_MakeTpCall
    (callable=<built-in method exec_ of QApplication object at remote 0x7fff8730fee0>, args=<optimized out>, nargs=<optimized out>, keywords=0x0) at Objects/call.c:159
#18 0x00007ffff7ca1603 in _PyObject_Vectorcall
    (kwnames=0x0, nargsf=<optimized out>, args=<optimized out>, callable=<built-in method exec_ of QApplication object at remote 0x7fff8730fee0>)
    at ./Include/cpython/abstract.h:125
#19 _PyObject_Vectorcall
    (kwnames=<optimized out>, nargsf=<optimized out>, args=<optimized out>, callable=<optimized out>) at ./Include/cpython/abstract.h:115
#20 call_function
    (tstate=tstate@entry=0x55555555ca50, pp_stack=pp_stack@entry=0x7fffffffc900, oparg=<optimized out>, kwnames=kwnames@entry=0x0) at Python/ceval.c:4963
#21 0x00007ffff7ca87b4 in _PyEval_EvalFrameDefault
    (f=<optimized out>, throwflag=<optimized out>) at Python/ceval.c:3469
#22 0x00007ffff7db005f in _PyEval_EvalCodeWithName
    (_co=<optimized out>, globals=globals@entry={'__name__': 'napari._qt.qt_event_loop', '__doc__': None, '__package__': 'napari._qt', '__loader__': <SourceFileLoader(name='napari._qt.qt_event_loop', path='/home/czaki/Projekty/napari/napari/_qt/qt_event_loop.py') at remote 0x7fff87309550>, '__spec__': <ModuleSpec(name='napari._qt.qt_event_loop', load--Type <RET> for more, q to quit, c to continue without paging--
er=<...>, origin='/home/czaki/Projekty/napari/napari/_qt/qt_event_loop.py', loader_state=None, submodule_search_locations=None, _set_fileattr=True, _cached='/home/czaki/Projekty/napari/napari/_qt/__pycache__/qt_event_loop.cpython-38.pyc', _initializing=False) at remote 0x7fff87309490>, '__file__': '/home/czaki/Projekty/napari/napari/_qt/qt_event_loop.py', '__cached__': '/home/czaki/Projekty/napari/napari/_qt/__pycache__/qt_event_loop.cpython-38.pyc', '__builtins__': {'__name__': 'builtins', '__doc__': "Built-in functions, exceptions, and other objects.\n\nNoteworthy: None is the `nil' object; Ellipsis represents `...' in slices.", '__package__': '', '__loader__': <type at remote 0x55555556d990>, '__spec__': <Mo...(truncated), locals=locals@entry=0x0, args=<optimized out>, argcount=0, kwnames=0x7ffff6e27bf8, kwargs=0x55555609a178, kwcount=1, kwstep=1, defs=0x0, defcount=0, kwdefs={'force': False, 'gui_exceptions': False, 'max_loop_level': 1, '_func_name': 'run'}, closure=0x0, name='run', qualname='run') at Python/ceval.c:4298
#23 0x00007ffff7cceee6 in _PyFunction_Vectorcall
    (func=<optimized out>, stack=<optimized out>, nargsf=<optimized out>, kwnames=<optimized out>) at Objects/call.c:435
#24 0x00007ffff7ca157d in _PyObject_Vectorcall
    (kwnames=<optimized out>, nargsf=<optimized out>, args=<optimized out>, callable=<optimized out>) at ./Include/cpython/abstract.h:127
#25 call_function
    (tstate=tstate@entry=0x55555555ca50, pp_stack=pp_stack@entry=0x7fffffffcbc0, oparg=<optimized out>, kwnames=kwnames@entry=('gui_exceptions',)) at Python/ceval.c:4963
#26 0x00007ffff7ca2d40 in _PyEval_EvalFrameDefault
    (f=<optimized out>, throwflag=<optimized out>) at Python/ceval.c:3515
--Type <RET> for more, q to quit, c to continue without paging--
#27 0x00007ffff7db005f in _PyEval_EvalCodeWithName
    (_co=<optimized out>, globals=globals@entry={'__name__': '__main__', '__doc__': '\nnapari command line viewer.\n', '__package__': 'napari', '__loader__': <SourceFileLoader(name='napari.__main__', path='/home/czaki/Projekty/napari/napari/__main__.py') at remote 0x7ffff6e7b700>, '__spec__': <ModuleSpec(name='napari.__main__', loader=<...>, origin='/home/czaki/Projekty/napari/napari/__main__.py', loader_state=None, submodule_search_locations=None, _set_fileattr=True, _cached='/home/czaki/Projekty/napari/napari/__pycache__/__main__.cpython-38.pyc') at remote 0x7ffff6e27490>, '__annotations__': {}, '__builtins__': <module at remote 0x7ffff708b090>, '__file__': '/home/czaki/Projekty/napari/napari/__main__.py', '__cached__': '/home/czaki/Projekty/napari/napari/__pycache__/__main__.cpython-38.pyc', 'argparse': <module at remote 0x7ffff6e34810>, 'logging': <module at remote 0x7ffff6e3f590>, 'os': <module at remote 0x7ffff7030ea0>, 'runpy': <module at remote 0x7ffff6e82590>, 'sys': <module at remote 0x7ffff707fe00>, 'warnings': <module at remote 0x7ffff6f84810>,...(truncated), locals=locals@entry=0x0, args=<optimized out>, argcount=0, kwnames=0x0, kwargs=0x7ffff6ec9f88, kwcount=0, kwstep=1, defs=0x0, defcount=0, kwdefs=0x0, closure=0x0, name='_run', qualname='_run') at Python/ceval.c:4298
#28 0x00007ffff7cceee6 in _PyFunction_Vectorcall (func=<optimized out>, stack=<optimized out>, nargsf=<optimized out>, kwnames=<optimized out>) at Objects/call.c:435
#29 0x00007ffff7ca157d in _PyObject_Vectorcall (kwnames=<optimized out>, nargsf=<optimized out>, args=<optimized out>, callable=<optimized out>) at ./Include/cpython/abstract.h:127
#30 call_function (tstate=tstate@entry=0x55555555ca50, pp_stack=pp_stack@entry=0x7fffffffce68, oparg=<optimized out>, kwnames=kwnames@entry=0x0) at Python/ceval.c:4963
#31 0x00007ffff7ca4c18 in _PyEval_EvalFrameDefault (f=<optimized out>, throwflag=<optimized out>) at Python/ceval.c:3500
#32 0x00007ffff7ca0263 in function_code_fastcall (co=<optimized out>, args=<optimized out>, nargs=0, globals=<optimized out>) at Objects/call.c:283
#33 0x00007ffff7ca157d in _PyObject_Vectorcall (kwnames=<optimized out>, nargsf=<optimized out>, args=<optimized out>, callable=<optimized out>) at ./Include/cpython/abstract.h:127
#34 call_function (tstate=tstate@entry=0x55555555ca50, pp_stack=pp_stack@entry=0x7fffffffd028, oparg=<optimized out>, kwnames=kwnames@entry=0x0) at Python/ceval.c:4963
#35 0x00007ffff7ca4c18 in _PyEval_EvalFrameDefault (f=<optimized out>, throwflag=<optimized out>) at Python/ceval.c:3500
#36 0x00007ffff7db005f in _PyEval_EvalCodeWithName
    (_co=_co@entry=<code at remote 0x7ffff6e28d40>, globals=globals@entry={'__name__': '__main__', '__doc__': '\nnapari command line viewer.\n', '__package__': 'napari', '__loader__': <SourceFileLoader(name='napari.__main__', path='/home/czaki/Projekty/napari/napari/__main__.py') at remote 0x7ffff6e7b700>, '__spec__': <ModuleSpec(name='napari.__main__', loader=<...>, origin='/home/czaki/Projekty/napari/napari/__main__.py', loader_state=None, submodule_search_locations=None, _set_fileattr=True, _cached='/home/czaki/Projekty/napari/napari/__pycache__/__main__.cpython-38.pyc') at remote 0x7ffff6e27490>, '__annotations__': {}, '__builtins__': <module at remote 0x7ffff708b090>, '__file__': '/home/czaki/Projekty/napari/napari/__main__.py', '__cached__': '/home/czaki/Projekty/napari/napari/__pycache__/__main__.cpython-38.pyc', 'argparse': <module at remote 0x7ffff6e34810>, 'logging': <module at remote 0x7ffff6e3f590>, 'os': <module at remote 0x7ffff7030ea0>, 'runpy': <module at remote 0x7ffff6e82590>, 'sys': <module at remote 0x7ffff707fe00>, 'warnings': <module at remote 0x7ffff6f84810>,...(truncated), locals=locals@entry={'__name__': '__main__', '__doc__': '\nnapari command line viewer.\n', '__package__': 'napari', '__loader__': <SourceFileLoader(name='napari.__main__', path='/home/czaki/Projekty/napari/napari/__main__.py') at remote 0x7ffff6e7b700>, '__spec__': <ModuleSpec(name='napari.__main__', loader=<...>, origin='/home/czaki/Projekty/napari/napari/__main__.py', loader_state=None, submodule_search_locations=None, _set_fileattr=True, _cached='/home/czaki/Projekty/napari/napari/__pycache__/__main__.cpython-38.pyc') at remote 0x7ffff6e27490>, '__annotations__': {}, '__builtins__': <module at remote 0x7ffff708b090>, '__file__': '/home/czaki/Projekty/napari/napari/__main__.py', '__cached__': '/home/czaki/Projekty/napari/napari/__pycache__/__main__.cpython-38.pyc', 'argparse': <module at remote 0x7ffff6e34810>, 'logging': <module at remote 0x7ffff6e3f590>, 'os': <module at remote 0x7ffff7030ea0>, 'runpy': <module at remote 0x7ffff6e82590>, 'sys': <module at remote 0x7ffff707fe00>, 'warnings': <module at remote 0x7ffff6f84810>,...(truncated), args=args@entry=0x0, argcount=argcount@entry=0, kwnames=kwnames@entry=0x0, kwargs=0x0, kwcount=0, kwstep=2, defs=0x0, defcount=0, kwdefs=0x0, closure=0x0, name=0x0, qualname=0x0) at Python/ceval.c:4298
#37 0x00007ffff7db0402 in PyEval_EvalCodeEx
    (_co=_co@entry=<code at remote 0x7ffff6e28d40>, globals=globals@entry={'__name__': '__main__', '__doc__': '\nnapari command line viewer.\n', '__package__': 'napari', '__loader__': <SourceFileLoader(name='napari.__main__', path='/home/czaki/Projekty/napari/napari/__main__.py') at remote 0x7ffff6e7b700>, '__spec__': <ModuleSpec(name='napari.__main__', loader=<...>, origin='/home/czaki/Projekty/napari/napari/__main__.py', loader_state=None, submodule_search_locations=None, _set_fileattr=True, _cached='/home/czaki/Projekty/napari/napari/__pycache__/__main__.cpython-38.pyc') at remote 0x7ffff6e27490>, '__annotations__': {}, '__builtins__': <module at remote 0x7ffff708b090>, '__file__': '/home/czaki/Projekty/napari/napari/__main__.py', '__cached__': '/home/czaki/Projekty/napari/napari/__pycache__/__main__.cpython-38.pyc', 'argparse': <module at remote 0x7ffff6e34810>, 'logging': <module at remote 0x7ffff6e3f590>, 'os': <module at remote 0x7ffff7030ea0>, 'runpy': <module at remote 0x7ffff6e82590>, 'sys': <module at remote 0x7ffff707fe00>, 'warnings': <module at remote 0x7ffff6f84810>,...(truncated), locals=locals@entry={'__name__': '__main__', '__doc__': '\nnapari command line viewer.\n', '__package__': 'napari', '__loader__': <SourceFileLoader(name='napari.__main__', path='/home/czaki/Projekty/napari/napari/__main__.py') at remote 0x7ffff6e7b700>, '__spec__': <ModuleSpec(name='napari.__main__', loader=<...>, origin='/home/czaki/Projekty/napari/napari/__main__.py', loader_state=None, submodule_search_locations=None, _set_fileattr=True, _cached='/home/czaki/Projekty/napari/napari/__pycache__/__main__.cpython-38.pyc') at remote 0x7ffff6e27490>, '__annotations__': {}, '__builtins__': <module at remote 0x7ffff708b090>, '__file__': '/home/czaki/Projekty/napari/napari/__main__.py', '__cached__': '/home/czaki/Projekty/napari/napari/__pycache__/__main__.cpython-38.pyc', 'argparse': <module at remote 0x7ffff6e34810>, 'logging': <module at remote 0x7ffff6e3f590>, 'os': <module at remote 0x7ffff7030ea0>, 'runpy': <module at remote 0x7ffff6e82590>, 'sys': <module at remote 0x7ffff707fe00>, 'warnings': <module at remote 0x7ffff6f84810>,...(truncated), args=args@entry=0x0, argcount=argcount@entry=0, kws=kws@entry=0x0, kwcount=0, defs=0x0, defcount=0, kwdefs=0x0, closure=0x0) at Python/ceval.c:4327
#38 0x00007ffff7db042f in PyEval_EvalCode
    (co=co@entry=<code at remote 0x7ffff6e28d40>, globals=globals@entry={'__name__': '__main__', '__doc__': '\nnapari command line viewer.\n', '__package__': 'napari', '__loader__': <SourceFileLoader(name='napari.__main__', path='/home/czaki/Projekty/napari/napari/__main__.py') at remote 0x7ffff6e7b700>, '__spec__': <ModuleSpec(name='napari.__main__', loader=<...>, origin='/home/czaki/Projekty/napari/napari/__main__.py', loader_state=None, submodule_search_locations=None, _set_fileattr=True, _cached='/home/czaki/Projekty/napari/napari/__pycache__/__main__.cpython-38.pyc') at remote 0x7ffff6e27490>, '__annotations__': {}, '__builtins__': <module at remote 0x7ffff708b090>, '__file__': '/home/czaki/Projekty/napari/napari/__main__.py', '__cached__': '/home/czaki/Projekty/napari/napari/__pycache__/__main__.cpython-38.pyc', 'argparse': <module at remote 0x7ffff6e34810>, 'logging': <module at remote 0x7ffff6e3f590>, 'os': <module at remote 0x7ffff7030ea0>, 'runpy': <module at remote 0x7ffff6e82590>, 'sys': <module at remote 0x7ffff707fe00>, 'warnings': <module at remote 0x7ffff6f84810>,...(truncated), locals=locals@entry={'__name__': '__main__', '__doc__': '\nnapari command line viewer.\n', '__package__': 'napari', '__loader__': <SourceFileLoader(name='napari.__main__', path='/home/czaki/Projekty/napari/napari/__main__.py') at remote 0x7ffff6e7b700>, '__spec__': <ModuleSpec(name='napari.__main__', loader=<...>, origin='/home/czaki/Projekty/napari/napari/__main__.py', loader_state=None, submodule_search_locations=None, _set_fileattr=True, _cached='/home/czaki/Projekty/napari/napari/__pycache__/__main__.cpython-38.pyc') at remote 0x7ffff6e27490>, '__annotations__': {}, '__builtins__': <module at remote 0x7ffff708b090>, '__file__': '/home/czaki/Projekty/napari/napari/__main__.py', '__cached__': '/home/czaki/Projekty/napari/napari/__pycache__/__main__.cpython-38.pyc', 'argparse': <module at remote 0x7ffff6e34810>, 'logging': <module at remote 0x7ffff6e3f590>, 'os': <module at remote 0x7ffff7030ea0>, 'runpy': <module at remote 0x7ffff6e82590>, 'sys': <module at remote 0x7ffff707fe00>, 'warnings': <module at remote 0x7ffff6f84810>,...(truncated)) at Python/ceval.c:718
#39 0x00007ffff7dacbb9 in builtin_exec_impl
    (module=<optimized out>, locals={'__name__': '__main__', '__doc__': '\nnapari command line viewer.\n', '__package__': 'napari', '__loader__': <SourceFileLoader(name='napari.__main__', path='/home/czaki/Projekty/napari/napari/__main__.py') at remote 0x7ffff6e7b700>, '__spec__': <ModuleSpec(name='napari.__main__', loader=<...>, origin='/home/czaki/Projekty/napari/napari/__main__.py', loader_state=None, submodule_search_locations=None, _set_fileat--Type <RET> for more, q to quit, c to continue without paging--
tr=True, _cached='/home/czaki/Projekty/napari/napari/__pycache__/__main__.cpython-38.pyc') at remote 0x7ffff6e27490>, '__annotations__': {}, '__builtins__': <module at remote 0x7ffff708b090>, '__file__': '/home/czaki/Projekty/napari/napari/__main__.py', '__cached__': '/home/czaki/Projekty/napari/napari/__pycache__/__main__.cpython-38.pyc', 'argparse': <module at remote 0x7ffff6e34810>, 'logging': <module at remote 0x7ffff6e3f590>, 'os': <module at remote 0x7ffff7030ea0>, 'runpy': <module at remote 0x7ffff6e82590>, 'sys': <module at remote 0x7ffff707fe00>, 'warnings': <module at remote 0x7ffff6f84810>,...(truncated), globals={'__name__': '__main__', '__doc__': '\nnapari command line viewer.\n', '__package__': 'napari', '__loader__': <SourceFileLoader(name='napari.__main__', path='/home/czaki/Projekty/napari/napari/__main__.py') at remote 0x7ffff6e7b700>, '__spec__': <ModuleSpec(name='napari.__main__', loader=<...>, origin='/home/czaki/Projekty/napari/napari/__main__.py', loader_state=None, submodule_search_locations=None, _set_fileattr=True, _cached='/home/czaki/Projekty/napari/napari/__pycache__/__main__.cpython-38.pyc') at remote 0x7ffff6e27490>, '__annotations__': {}, '__builtins__': <module at remote 0x7ffff708b090>, '__file__': '/home/czaki/Projekty/napari/napari/__main__.py', '__cached__': '/home/czaki/Projekty/napari/napari/__pycache__/__main__.cpython-38.pyc', 'argparse': <module at remote 0x7ffff6e34810>, 'logging': <module at remote 0x7ffff6e3f590>, 'os': <module at remote 0x7ffff7030ea0>, 'runpy': <module at remote 0x7ffff6e82590>, 'sys': <module at remote 0x7ffff707fe00>, 'warnings': <module at remote 0x7ffff6f84810>,...(truncated), source=<code at remote 0x7ffff6e28d40>) at Python/bltinmodule.c:1033
#40 builtin_exec (module=<optimized out>, args=0x555555627dd0, nargs=<optimized out>) at Python/clinic/bltinmodule.c.h:396
#41 0x00007ffff7d15b17 in cfunction_vectorcall_FASTCALL (func=<built-in method exec of module object at remote 0x7ffff708b090>, args=<optimized out>, nargsf=<optimized out>, kwnames=<optimized out>)
    at Objects/methodobject.c:422
#42 0x00007ffff7ca157d in _PyObject_Vectorcall (kwnames=<optimized out>, nargsf=<optimized out>, args=<optimized out>, callable=<optimized out>) at ./Include/cpython/abstract.h:127
#43 call_function (tstate=tstate@entry=0x55555555ca50, pp_stack=pp_stack@entry=0x7fffffffd378, oparg=<optimized out>, kwnames=kwnames@entry=0x0) at Python/ceval.c:4963
#44 0x00007ffff7ca4c18 in _PyEval_EvalFrameDefault (f=<optimized out>, throwflag=<optimized out>) at Python/ceval.c:3500
#45 0x00007ffff7db005f in _PyEval_EvalCodeWithName
    (_co=<optimized out>, globals=globals@entry={'__name__': 'runpy', '__doc__': 'runpy.py - locating and running Python code using the module namespace\n\nProvides support for locating and running Python scripts using the Python\nmodule namespace instead of the native filesystem.\n\nThis allows Python code to play nicely with non-filesystem based PEP 302\nimporters when locating support scripts as well as when importing modules.\n', '__package__': '', '__loader__': <SourceFileLoader(name='runpy', path='/home/czaki/.pyenv/versions/3.8.3/lib/python3.8/runpy.py') at remote 0x7ffff6e7b9a0>, '__spec__': <ModuleSpec(name='runpy', loader=<...>, origin='/home/czaki/.pyenv/versions/3.8.3/lib/python3.8/runpy.py', loader_state=None, submodule_search_locations=None, _set_fileattr=True, _cached='/home/czaki/.pyenv/versions/3.8.3/lib/python3.8/__pycache__/runpy.cpython-38.pyc', _initializing=False) at remote 0x7ffff6e7b640>, '__file__': '/home/czaki/.pyenv/versions/3.8.3/lib/python3.8/runpy.py', '__cached__': '/home/czaki/.pyenv/versions/3.8.3/lib/python3.8/__pycache__...(truncated), locals=locals@entry=0x0, args=<optimized out>, argcount=5, kwnames=0x0, kwargs=0x55555562d8f0, kwcount=0, kwstep=1, defs=0x7ffff6e82be8, defcount=5, kwdefs=0x0, closure=0x0, name='_run_code', qualname='_run_code') at Python/ceval.c:4298
#46 0x00007ffff7cceee6 in _PyFunction_Vectorcall (func=<optimized out>, stack=<optimized out>, nargsf=<optimized out>, kwnames=<optimized out>) at Objects/call.c:435
#47 0x00007ffff7ca157d in _PyObject_Vectorcall (kwnames=<optimized out>, nargsf=<optimized out>, args=<optimized out>, callable=<optimized out>) at ./Include/cpython/abstract.h:127
#48 call_function (tstate=tstate@entry=0x55555555ca50, pp_stack=pp_stack@entry=0x7fffffffd628, oparg=<optimized out>, kwnames=kwnames@entry=0x0) at Python/ceval.c:4963
#49 0x00007ffff7ca4c18 in _PyEval_EvalFrameDefault (f=<optimized out>, throwflag=<optimized out>) at Python/ceval.c:3500
#50 0x00007ffff7db005f in _PyEval_EvalCodeWithName
    (_co=<optimized out>, globals=globals@entry={'__name__': 'runpy', '__doc__': 'runpy.py - locating and running Python code using the module namespace\n\nProvides support for locating and running Python scripts using the Python\nmodule namespace instead of the native filesystem.\n\nThis allows Python code to play nicely with non-filesystem based PEP 302\nimporters when locating support scripts as well as when importing modules.\n', '__package__': '', '__loader__': <SourceFileLoader(name='runpy', path='/home/czaki/.pyenv/versions/3.8.3/lib/python3.8/runpy.py') at remote 0x7ffff6e7b9a0>, '__spec__': <ModuleSpec(name='runpy', loader=<...>, origin='/home/czaki/.pyenv/versions/3.8.3/lib/python3.8/runpy.py', loader_state=None, submodule_search_locations=None, _set_fileattr=True, _cached='/home/czaki/.pyenv/versions/3.8.3/lib/python3.8/__pycache__/runpy.cpython-38.pyc', _initializing=False) at remote 0x7ffff6e7b640>, '__file__': '/home/czaki/.pyenv/versions/3.8.3/lib/python3.8/runpy.py', '__cached__': '/home/czaki/.pyenv/versions/3.8.3/lib/python3.8/__pycache__...(truncated), locals=locals@entry=0x0, args=<optimized out>, argcount=2, kwnames=0x0, kwargs=0x7ffff6e7c368, kwcount=0, kwstep=1, defs=0x7ffff7037b98, defcount=1, kwdefs=0x0, closure=0x0, name='_run_module_as_main', qualname='_run_module_as_main') at Python/ceval.c:4298
#51 0x00007ffff7cceee6 in _PyFunction_Vectorcall (func=func@entry=<function at remote 0x7ffff6e1caf0>, stack=<optimized out>, nargsf=nargsf@entry=2, kwnames=<optimized out>) at Objects/call.c:435
#52 0x00007ffff7cd0fd3 in PyVectorcall_Call (callable=<function at remote 0x7ffff6e1caf0>, tuple=<optimized out>, kwargs=<optimized out>) at Objects/call.c:199
#53 0x00007ffff7e10140 in pymain_run_module (modname=<optimized out>, set_argv0=set_argv0@entry=1) at Modules/main.c:302
#54 0x00007ffff7e1078a in pymain_run_python (exitcode=0x7fffffffd8ac) at Modules/main.c:559
#55 Py_RunMain () at Modules/main.c:644
#56 0x00007ffff7e10f8a in pymain_main (args=0x7fffffffd9b0) at Modules/main.c:674
#57 Py_BytesMain (argc=<optimized out>, argv=<optimized out>) at Modules/main.c:698
#58 0x00007ffff7a0cd90 in __libc_start_call_main (main=main@entry=0x555555555060 <main>, argc=argc@entry=3, argv=argv@entry=0x7fffffffdb38) at ../sysdeps/nptl/libc_start_call_main.h:58
#59 0x00007ffff7a0ce40 in __libc_start_main_impl (main=0x555555555060 <main>, argc=3, argv=0x7fffffffdb38, init=<optimized out>, fini=<optimized out>, rtld_fini=<optimized out>, stack_end=0x7fffffffdb28)
    at ../csu/libc-start.c:392
#60 0x000055555555509e in _start ()
```

It looks like error is when ending some animation. Animation that may be started from thread. any idea? 
Reproduced a few more times, and all times it was connected with Animation. Some of the crashes were when napari was in the background (or when changing focus). So it may not be directly caused by a mouse move.
could it be https://github.com/napari/napari/pull/4761?
https://github.com/napari/napari/pull/4761 makes sense in terms of the timing/recency and because there are threads involved, but the non-test code changes are small and I don't immediately see how they would cause this bug, especially if playback has not started (in which cases `QtDims.stop` should do nothing interesting).
yeah, totally agree.  Seems like such a minimal and correct change, it's only the recency that makes me bring it up
I was able to reproduce this pretty easily on `main` (cb65683b4e32ac2ed241de8213d1a7f551da479e). I also just checked out the commit before that got merged (97aa23ccb843f80bf660a93ec80e484c5de0b2d6) and reproduced it almost immediately.

I don't have a good way to reproduce this other than manual interaction, but maybe I'll try a semi-guided binary search to find some candidates.
> I was able to reproduce this pretty easily on main (https://github.com/napari/napari/commit/cb65683b4e32ac2ed241de8213d1a7f551da479e). I also just checked out the commit before that got merged (https://github.com/napari/napari/commit/97aa23ccb843f80bf660a93ec80e484c5de0b2d6) and reproduced it almost immediately.

awesome.  thanks for checking and letting us rule that out :)
One other thought is that this might have been around longer than we realize. Given this about threading, mouse movements, and @Czaki's mention of lots of thread being created, the use of `throttled` also comes to mind: https://github.com/napari/napari/blob/cb65683b4e32ac2ed241de8213d1a7f551da479e/napari/components/viewer_model.py#L203

I did quickly try adding `@ensure_main_thread` to `_update_status_bar_from_cursor` and I couldn't reproduce the issue after about 60 seconds of various mousey interactions, but that's pretty flaky evidence. And I don't have a coherent explanation of what is causing the bug, so not great.
>  the use of throttled also comes to mind:

yeah, that was becoming my next suspicion as well!  i think you're right.

> I did quickly try adding @ensure_main_thread to _update_status_bar_from_cursor and I couldn't reproduce the issue after about 60 seconds of various mousey interactions

fascinating... yeah, that probably means that using `throttled` is relatively risky.  I wonder if using `qthrottled` (from superqt instead of psygnal) would fix that bug there (the same way that ensure_main_thread did)?  using qthrottled there isn't a good solution, since that callback is being connected in viewer_model, outside of qt land (hence using the psygnal one).  But this all harkens back to #4738 basically i think.

> I wonder if using `qthrottled` (from superqt instead of psygnal) would fix that bug there (the same way that ensure_main_thread did)?

Probably? Mostly because that uses a `QTimer` (which does not create any extra threads AFAIK). But like you mentioned `qthrottled` is a little riskier/harder to use than `@ensure_main_thread` in terms of dependencies and future compatibility.

Again, not sure if this is actually the fix, but it's probably worth doing anyway at described in #4738. At a minimum adding `@ensure_main_thread` to things a little deeper like `QMainWindow._status_change` might be a good next step.
> Mostly because that uses a `QTimer` (which does not create any extra threads AFAIK)

yep, looks like you're right.  [This SO post](https://stackoverflow.com/a/42311174) was pretty educational.  

arg... it's just tough to implement asynchronous callbacks in python in a backend agnostic way! :joy: ...
I definitely agree with your proposal that we just go ahead and decorate with `ensure_main_thread` ... and I'd even be happy just putting it directly on `QMainWindow._status_change`.

maybe it's time to dig back into the asyncio stuff? :joy:
> fascinating... yeah, that probably means that using `throttled` is relatively risky.

yes. After look into implementation it is amazing that it requires so many things to crash. 

Could we just simple move this (and all other that using throtled) to QMainWindow constructor (and use qthrotler)? https://github.com/napari/napari/blob/cb65683b4e32ac2ed241de8213d1a7f551da479e/napari/components/viewer_model.py#L203


yeah, that seems like a good plan to me.  "update status bar" is a strictly gui related thing, so that should probably have been on the `_qt` side of things all along
This is happening for me almost every time I open napari on `main`, so it's like there was some recent change that made this more likely.

Maybe the changes to the status bar in https://github.com/napari/napari/pull/4664 exposed the multi-threading bug caused by `throttled` to occur more frequently? Anyway, I plan to submit a quick fix for ensuring qwidget updates run on the main thread.
> This is happening for me almost every time I open napari on main, so it's like there was some recent change that made this more likely.

yeah, perhaps the confluence of throttled, #4664, and #4814 brought it up.  

@andy-sweet I see you self-assigned... thanks.  and let me know if you want me to do anything
I found it tricky to move the connection and use `qthrottled` because I'm unsure about expectations for headless napari users. See the description of #4983 for more details. Feel free to implement alternatives - I'll be away for a couple of hours.

Resolving patch:
diff --git a/napari/_qt/qt_main_window.py b/napari/_qt/qt_main_window.py
--- a/napari/_qt/qt_main_window.py
+++ b/napari/_qt/qt_main_window.py
@@ -35,7 +35,7 @@
     QToolTip,
     QWidget,
 )
-from superqt import ensure_main_thread
+from superqt.utils import QSignalThrottler
 
 from ..plugins import menu_item_template as plugin_menu_item_template
 from ..plugins import plugin_manager
@@ -133,6 +133,20 @@ def __init__(self, viewer: 'Viewer', parent=None) -> None:
                 self._qt_viewer.canvas._backend.screen_changed
             )
 
+        self.status_throttler = QSignalThrottler(parent=self)
+        self.status_throttler.setTimeout(50)
+
+        # In the GUI we expect lots of changes to the cursor position, so
+        # replace the direct connection with a throttled one.
+        with contextlib.suppress(IndexError):
+            viewer.cursor.events.position.disconnect(
+                viewer._update_status_bar_from_cursor
+            )
+        viewer.cursor.events.position.connect(self.status_throttler.throttle)
+        self.status_throttler.triggered.connect(
+            viewer._update_status_bar_from_cursor
+        )
+
     def statusBar(self) -> 'ViewerStatusBar':
         return super().statusBar()
 
@@ -280,6 +294,8 @@ def _save_current_window_settings(self):
 
     def close(self, quit_app=False, confirm_need=False):
         """Override to handle closing app or just the window."""
+        if hasattr(self.status_throttler, "_timer"):
+            self.status_throttler._timer.stop()
         if not quit_app and not self._qt_viewer.viewer.layers:
             return super().close()
         if (
@@ -1143,7 +1159,6 @@ def _update_theme(self, event=None):
 
             self._qt_window.setStyleSheet(get_stylesheet(value))
 
-    @ensure_main_thread
     def _status_changed(self, event):
         """Update status bar.
 
@@ -1173,7 +1188,6 @@ def _title_changed(self, event):
         """
         self._qt_window.setWindowTitle(event.value)
 
-    @ensure_main_thread
     def _help_changed(self, event):
         """Update help message on status bar.
 
diff --git a/napari/components/viewer_model.py b/napari/components/viewer_model.py
--- a/napari/components/viewer_model.py
+++ b/napari/components/viewer_model.py
@@ -20,7 +20,6 @@
 )
 
 import numpy as np
-from psygnal import throttled
 from pydantic import Extra, Field, validator
 
 from .. import layers
@@ -199,7 +198,7 @@ def __init__(self, title='napari', ndisplay=2, order=(), axis_labels=()):
         self.dims.events.order.connect(self.reset_view)
         self.dims.events.current_step.connect(self._update_layers)
         self.cursor.events.position.connect(
-            throttled(self._update_status_bar_from_cursor, timeout=50)
+            self._update_status_bar_from_cursor
         )
         self.layers.events.inserted.connect(self._on_add_layer)
         self.layers.events.removed.connect(self._on_remove_layer)
diff --git a/napari/utils/_testsupport.py b/napari/utils/_testsupport.py
--- a/napari/utils/_testsupport.py
+++ b/napari/utils/_testsupport.py
@@ -74,8 +74,6 @@ def napari_plugin_manager(monkeypatch):
     Or, to re-enable global discovery, use:
     `napari_plugin_manager.discovery_blocker.stop()`
     """
-    from unittest.mock import patch
-
     import napari
     import napari.plugins.io
     from napari.plugins._plugin_manager import NapariPluginManager


Test patch:
diff --git a/napari/_tests/test_multiple_viewers.py b/napari/_tests/test_multiple_viewers.py
--- a/napari/_tests/test_multiple_viewers.py
+++ b/napari/_tests/test_multiple_viewers.py
@@ -1,7 +1,10 @@
+import gc
+from unittest.mock import patch
+
 from napari import Viewer
 
 
-def test_multi_viewers_dont_clash(qapp):
+def test_multi_viewers_dont_clash(qtbot):
     v1 = Viewer(show=False, title='v1')
     v2 = Viewer(show=False, title='v2')
     assert not v1.grid.enabled
@@ -13,5 +16,9 @@ def test_multi_viewers_dont_clash(qapp):
     assert not v2.grid.enabled
     assert v1.grid.enabled
 
-    v1.close()
-    v2.close()
+    with patch.object(v1.window._qt_window, '_save_current_window_settings'):
+        v1.close()
+    with patch.object(v2.window._qt_window, '_save_current_window_settings'):
+        v2.close()
+    qtbot.wait(50)
+    gc.collect()