threadId in ParallelizeImageRegion

Hi,

I’m trying to use itk::MultiThreaderBase and ParallelizeImageRegion for the first time. I managed to get it working for one task, so I’m on the right track. But for another task, I need the threads to be able to access their threadId. This thread Multi-threader refactoring suggests that ParallelizeImageRegion used to have a threadId argument, but it was removed. I’m guessing there still is a way to access the threadId, but I can’t find it.

Regards,
Cyril

1 Like

Hi @cyril.mory,
although @dzenanz will be able to provide a far better explanation than me on the question, if you need the thread number, the backwards-compatibility can be achieved by calling
this->DynamicMultiThreadingOff();.

You can find additional explanations on the issue in the ITK SW Guide, section 3.2.7

HTH,
JON HAITZ

Hi Cyril,

As @jhlegarreta mentioned, we are testing and documenting ways to address the migration beyond threadId in the ITK Software Guide and ITK 5 Migration Guide. threadId is no longer available for performance reasons. See the discussion here:

Multi-threader refactoring

Currently, a workaround is to call this>DynamicMultiThreadingOff() in the filter constructor. This will use the old, non-Dynamic method, with a threadId but it is also limited to the previous threading backend.

However, there are only a few common patterns where threadId appears to have been applied. We are working on testing and documenting alternative approaches for these patterns that work with the new dynamic backends. For example,

  1. Intermediate values are accumulated in each work unit
  2. Counting is accumulated

What is the use case in your filter for threadId?

Thanks,
Matt

1 Like

I am refactoring the ConjugateGradientImageFilter in RTK (www.openrtk.org), and at several points in the conjugate gradient algorithm, one needs to compute accumulations.
Since one also needs to apply a linear operator that can be quite complex, which I implemented as a filter, I cannot write the ConjugateGradientImageFilter as a full-blown multi-threaded filter. Which is why I got interested in ParallelizeImageRegion() and the ability it provides to run some multi-threaded code in an otherwise single-threaded GenerateData() method.

Do you think the alternative approaches you mention for multi-threaded accumulation could be available soon ?

Best,
Cyril

1 Like

A simple approach that could work in the mean time, is just to add a lock to the accumulator at the end of the threaded method to control access to the final accumulation variable.

Yes, that would work indeed. I have never used ITK’s locks, though. Is there a simple example I could start from ?

There are two components to be aware of:

The mutex is variable scoped to provide serialized access. For your case, the need is to control access to threads in an instance of the class. So you are looking at a lock with object scope, a member variable.

The holder provides exception safe lock/unlock handling of the mutex via RAII.

Here is an example which controls initialization and access to a global variable:
https://github.com/InsightSoftwareConsortium/ITK/blob/master/Modules/Core/Common/src/itkMersenneTwisterRandomVariateGenerator.cxx#L62-L72 line 62 to really the only line that does it.

Folks are traveling for the summer, so it may be about a month or two.

Thanks for your help: I managed to get it to work using SimpleFastMutexLock and MutexLockHolder.

Regards,
Cyril

1 Like

If the accumulated variable is of simple type, wrapping it in std::atomic would probably be both shorter code-wise and have better performance than using locks.