Hello Developers,
As you might have already noticed, I have been trying all the development options in Slicer.
I am now working on using Loadable module for heavy computations while the remaining part of my code will be in scripted module.
My question is, can we run the computations on loadable module in the background. I want that user keep on interacting with the slicer while heavy computations runs on the background. This is possible in CLI. But I want to use loadable module.
Yes, you can do computations in the background in a loadable module. You can use any threading APIs (C++11 multithreading, VTK’s vtkMultiThreader, Qt threads, etc.).
The only tricky part is synchronization with the main thread. You are only allowed to modify MRML nodes or invoke MRML events from the main thread.
Thank you @lassoan for your response. Is there any example code for implementing this multithreading operation in Slicer?
I just want that the mouse interaction should not be effected with these computations.
OpenIGTLinkIF module does this. It is not easy to use it as an example, as the module is quite complex, but maybe if you add a breakpoint where an image is received and step through in a debugger then you can get an idea how it works.
Hello @lassoan,
Thank you for your response. Since my problem is quite simple I have tried pthread functions.
it seems to work, but still I cannot interact with the slicer window while my module is doing the computation.
its worth mentioning that, I haven’t added any MRML Node in my loadable module. I am just wroking with vtkFloatArray.
void *test2(void *ptr)
{
vtkFloatArray *a;
a=(vtkFloatArray *) ptr;
int c[2];
double Signal[49];
double test;
cout << "loading signal values.. " << std::endl;
int t=0;
for (int i=0;i<96;i++)
{ for (int j=0;j<128;j++)
{for (int k=0;k<128;k++)
{for (int l=0;l<49;l++)
{t=i+(96*j)+((96*128)*k)+((96*128*128)*l);
Signal[l]=a->GetValue(t);
}
}}}
return NULL;
}
And I am calling this function with
int err = pthread_create(&(tid[2]), NULL, test2, (void*) &a);
The code doesn’t mean anything, but I just want to run ‘test2’ pat of the code in other thread. (not in the main thread) so that my interaction wont get effected.
Creating a thread should not block the main thread. I would not recommend pthreads, as it is ancient unix-specific API. You can use C++11 multithreading, VTK’s vtkMultiThreader, or Qt threads instead.
Thank you @lassoan for your response, I am actually combining Scripted module and Loadable module. so my code is little messy. I can just add the important part here, so it might be easier for you:
The part of the code from my Scripted module (Python):
def onCheckBootstrap(self):
modlog = slicer.vtkSlicerBootstrapping_loadableLogic()
aa = (np.random.randint(0, 100, size=(96, 128, 128, 49)))
a = numpy_support.numpy_to_vtk(num_array=aa.ravel(), deep=True, array_type=vtk.VTK_FLOAT)
bb = (np.random.randint(0, 100, size=(49, 6)))
b = numpy_support.numpy_to_vtk(num_array=bb.ravel(), deep=True, array_type=vtk.VTK_FLOAT)
c=modlog.Test(a,b)
print ("Back to python:")
print(c)
So, you must not call pthread_join. You need to signal completion using alternative mechanisms. Polling a thread-safe queue object using a timer is simple and you can implement it using any of the threading/synchronization libraries. However, if you want to have minimal latency and synchronization overhead then probably you need to use proper synchronization objects.