Managing queue in multiple threads

I have a filter that is multithreaded but the time per thread may vary a lot. When I run it, OTB will launch the threads by bunch (depending on the number of CPU available), then it will wait until all the processes end before launching a new bunch. Is it possible to ask the threadedGenerateData to continuously launch threads instead of waitng for the end of a bunch?

Hello,

I don’t think this is possible with the ITK pipeline framework. To process a block of data (the “Requested Region”), ITK::ProcessObject::UpdateOutputData does the following (this is simplified !):

  • it calls UpdateOutputData on all inputs of the filter.
  • it calls GenerateData(), which in turns (for ImageSource, ImageToImageFilter etc …) :
    • Allocates the Output image
    • Calls BeforeThreadedGenerateData()
    • Splits the requested region into N regions, N being the number of threads available
    • Spawns N threads and call ThreadedGenerateData(...) in each thread
    • Wait until all threads completed their execution
    • Calls AfterThreadedGenerateData()

This means that in a filter, if you override ThreadedGenerateData, you don’t have much control on how the method is called, by design of the Streaming/Threading mechanism: The process is first streamed, and then threaded, if that makes sense.

If you want to have more control on the streaming, you can override GenerateData to bypass the ITK threading mechanism and implement threading as required.

I hope that helps,
Cédric

Thank you Cédric for the explanation. And is there a method to know the number of blocks that will be used (like this->GetNumberOfThreads() but for the number of blocks.

Unlike the number of thread, the number of blocks depends of the pipeline used and is computed by the ImageFileWriter at the end of the pipeline, and more specificaly by the StreamingManager object stored by the ImageFileWriter. You can call the GetNumerOfSplits() method of the StreamingManager to get the number of blocks that will be used. Note that PrepareStreming() should be called beforehand.

For instance you could write ;

writer->SetInput(filter->GetOutput());
writer->GenerateOutputInformation(); // This will call PrepareStreaming()  on the streaming manager
auto numberOfBlocks = writer->GetStreamingManager()->GetNumberOfSplits();

(untested)

Note that if you want to control the number of splits (instead of having it computed using the RAM) you can use the following methods:

writer->SetNumberOfDivisionsStrippedStreaming(i); // Stripped streaming with i divisions
writer->SetNumberOfDivisionsTiledStreaming(i); // Tiled streaming with i divisions
writer->SetNumberOfLinesStrippedStreaming(i); // Stripped streaming with i line per strip
writer->SetTileDimensionTiledStreaming(i); // Tiled streaming with square tiles of size i x i
writer->SetAutomaticTiledStreaming(ram); // RAM driven tiled streaming
writer->SetAutomaticStrippedStreaming(ram); // RAM driver stripped streaming
writer->SetAutomaticAdaptativeStreaming(ram); // RAM driven tiled streaming that will try to match the TileSize of the input image(s).

You can also use the extended filenames (streaming options).

Cédric