Observer crashes with Python thread, bug in vtkPythonCommand and also in dataset_adapter
This issue was created automatically from an original Mantis Issue. Further discussion may take place here.
Currently, if an observer is added in a python thread and then executed in another thread after the first one has finished, it will cause a segfault/access violation in the python interpreter.
This code reproduces the problem:
from Queue import Queue
from threading import Thread
import vtk
def on_delete(caller, event):
print 'on_delete:'
print ' caller:', caller
print ' event:', event
def create_object_with_observer(result_queue):
object_with_observer = vtk.vtkObject()
object_with_observer.AddObserver('DeleteEvent', on_delete)
result_queue.put(object_with_observer)
def test_observer_command_with_threads():
result_queue = Queue()
thread = Thread(target=create_object_with_observer, args=(result_queue,))
thread.start()
thread.join()
object_with_observer = result_queue.get(block=True)
print object_with_observer
del object_with_observer # <-- crashes here
print 'checkpoint'
if __name__ == '__main__':
test_observer_command_with_threads()
This seems to happen because of this line in vtkPythonCommand.cxx, which seems to be assigning a bad ThreadState pointer to _PyThreadState_Current:
prevThreadState = PyThreadState_Swap(this->ThreadState);
(The pointer seems to be dangling. Perhaps vtkPythonCommand::SetThreadState should incref the PyThreadState* object?)
This bug is directly affecting dataset_adapter, because it causes a crash in this use case (dataset_adapter uses a command to store the numpy array ref):
from Queue import Queue
from threading import Thread
from vtk.numpy_interface.dataset_adapter import UnstructuredGrid
import numpy
import vtk
def create_unstructured_grid(result_queue):
points = numpy.array([[0.0, 0.0, 0.0]])
ug = UnstructuredGrid(vtk.vtkUnstructuredGrid())
ug.SetPoints(points)
result_queue.put(ug)
def test_unstructured_grid_in_thread():
result_queue = Queue()
thread1 = Thread(target=create_unstructured_grid, args=(result_queue,))
thread1.start()
thread1.join()
ug = result_queue.get(block=True)
print ug
del ug # <-- crashes
print 'checkpoint'
if __name__ == '__main__':
test_unstructured_grid_in_thread()