Reading, Filtering and Writing in multiple threads

Hello everyone ( again :D),

Are there any resources or tips on running a function like this

void multiStaple(std::vector<std::string> inputfiles)
{
        // itk::MultiLabelSTAPLEImageFilter Type
	FilterType::Pointer filter = FilterType::New();
	filter->SetLabelForUndecidedPixels(0);
	filter->SetMaximumNumberOfIterations(1);

	for (size_t i = 0; i < inputfiles.size(); i++)
	{
		ReaderType::Pointer reader = ReaderType::New();
		reader->SetFileName(inputfiles[i]);

		try {
			reader->SetNumberOfThreads(1);
			reader->Update();
		}
		catch (itk::ExceptionObject& error) {
			mu.lock();
			std::cerr << "Error: " << error << std::endl;
			mu.unlock();
		}

		filter->SetInput(i, reader->GetOutput());
	}

	try {
		filter->SetNumberOfThreads(1);
		filter->Update();
	}
	catch (itk::ExceptionObject& error) {
		mu.lock();
		std::cerr << "Error: " << error << std::endl;
		mu.unlock();
	}

	WriterType::Pointer writer = WriterType::New();
	std::string outputFilename = inputfiles[0];
	std::string outputFilepath = std::filesystem::path(outputFilename).parent_path().string() + "\\" + outputFilename + "_filtered.nii";
	
	mu.lock();
	std::cout << "Writing: " << outputFilepath << std::endl;
	mu.unlock();

	writer->SetFileName(outputFilepath);
	writer->SetInput(filter->GetOutput());

	try {
		writer->SetNumberOfThreads(1);
		writer->Update();
	}
	catch (itk::ExceptionObject& error)
	{
		mu.lock();
		std::cerr << "Error: " << error << std::endl;
		mu.unlock();
	}
}

in multiple std::threads like

for (int i = 0; i < maxNumberOfThreads; ++i) {
	threadPool.emplace_back(std::thread(multiStaple, filesets[i]));
}
			
for (std::thread& th : threadPool) {
	th.join();
}

Because, as far as I know now, the itk::MultiLabelSTAPLEImageFilter does not have an implementation of ThreadedGenerateData() (taken from ImageToImageFilter). Therefore it should be theoretically possible to start multiple threads working on different image data, or am I wrong?

When I let it run with a single thread, everything works fine. If I start more than one thread, I get ITK Exceptions during execution. Are there any multithreaded accesses I am not aware of the reader, filter, and writer? In theory, there are no shared resources between the threads, as I only need to run the StapleFilter on multiple different data sets. I could not find any examples of letting filters run in parallel. I would be very grateful if you could show me some, given there are some.

Any suggestions are highly appreciated, as always!

Hi Keyn,

Most ITK filters are already parallelized. Meaning, based on the numbers of CPU cores/threads they will try to process data using multiple threads. I am not sure about the IO modules in particular, but this makes less sense ( due to serial nature of IO devices).

So maybe what you truly need is non-blocking (background) processing. There are several ways to achieve it via modern c++, probably the easiest is to use async calls (fire and forget).

Also, no offense, but it is clear you are not experienced in the domain of multi thread programming, maybe you need to start with simpler, isolated examples and build from there.

Best regards.

1 Like

Which exceptions are you getting? Your approach to parallelism sounds fine. How is your threadPool defined?

1 Like

Thank you, @pip010, for your response. I highly appreciate the feedback. I only have experience with the Qt concurrent framework, and the std::threads are indeed new to me. But it appears to me that the fire and forget principle you described is exactly what I tried to replicate - and it turns out it also worked fine after I fixed an issue I had within the filesets vector itself.

Thank you as well, @dzenanz, for confirming the idea behind my approach to it. It turns out the faulty point was not the thread handling itself. It was a mistake in the filesets vector I provided to the std::threads where I had a sorting issue, meaning the origin of the exception was trying to process the wrong files with different labels and sizes. When I managed to fix the problem, the code ran just as expected!

Again, thank you both so much, and sorry that it took me so long to respond, as I was occupied with a different project.

1 Like