Developer documentation
Version 3.0.3-105-gd3941f44
threaded_loop.h
Go to the documentation of this file.
1/* Copyright (c) 2008-2022 the MRtrix3 contributors.
2 *
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 *
7 * Covered Software is provided under this License on an "as is"
8 * basis, without warranty of any kind, either expressed, implied, or
9 * statutory, including, without limitation, warranties that the
10 * Covered Software is free of defects, merchantable, fit for a
11 * particular purpose or non-infringing.
12 * See the Mozilla Public License v. 2.0 for more details.
13 *
14 * For more details, see http://www.mrtrix.org/.
15 */
16
17#ifndef __algo_threaded_loop_h__
18#define __algo_threaded_loop_h__
19
20#include "debug.h"
21#include "algo/loop.h"
22#include "algo/iterator.h"
23#include "thread.h"
24
25namespace MR
26{
27
243 namespace {
244
245 inline vector<size_t> get_inner_axes (const vector<size_t>& axes, size_t num_inner_axes) {
246 return { axes.begin(), axes.begin()+num_inner_axes };
247 }
248
249 inline vector<size_t> get_outer_axes (const vector<size_t>& axes, size_t num_inner_axes) {
250 return { axes.begin()+num_inner_axes, axes.end() };
251 }
252
253 template <class HeaderType>
254 inline vector<size_t> get_inner_axes (const HeaderType& source, size_t num_inner_axes, size_t from_axis, size_t to_axis) {
255 return get_inner_axes (Stride::order (source, from_axis, to_axis), num_inner_axes);
256 }
257
258 template <class HeaderType>
259 inline vector<size_t> get_outer_axes (const HeaderType& source, size_t num_inner_axes, size_t from_axis, size_t to_axis) {
260 return get_outer_axes (Stride::order (source, from_axis, to_axis), num_inner_axes);
261 }
262
263
264 template <int N, class Functor, class... ImageType>
265 struct ThreadedLoopRunInner
266 { MEMALIGN(ThreadedLoopRunInner<N,Functor,ImageType...>)
267 const vector<size_t>& outer_axes;
268 decltype (Loop (outer_axes)) loop;
269 typename std::remove_reference<Functor>::type func;
270 std::tuple<ImageType...> vox;
271
272 ThreadedLoopRunInner (const vector<size_t>& outer_axes, const vector<size_t>& inner_axes,
273 const Functor& functor, ImageType&... voxels) :
274 outer_axes (outer_axes),
275 loop (Loop (inner_axes)),
276 func (functor),
277 vox (voxels...) { }
278
279 void operator() (const Iterator& pos) {
280 assign_pos_of (pos, outer_axes).to (vox);
281 for (auto i = unpack (loop, vox); i; ++i)
282 unpack (func, vox);
283 }
284 };
285
286
287 template <class Functor, class... ImageType>
288 struct ThreadedLoopRunInner<0,Functor,ImageType...>
289 { MEMALIGN(ThreadedLoopRunInner<0, Functor,ImageType...>)
290 const vector<size_t>& outer_axes;
291 decltype (Loop (outer_axes)) loop;
292 typename std::remove_reference<Functor>::type func;
293
294 ThreadedLoopRunInner (const vector<size_t>& outer_axes, const vector<size_t>& inner_axes,
295 const Functor& functor, ImageType&... /*voxels*/) :
296 outer_axes (outer_axes),
297 loop (Loop (inner_axes)),
298 func (functor) { }
299
300 void operator() (Iterator& pos) {
301 for (auto i = loop (pos); i; ++i)
302 func (pos);
303 }
304 };
305
306
307 inline void __manage_progress (...) { }
308 template <class LoopType, class ThreadType>
309 inline auto __manage_progress (const LoopType* loop, const ThreadType* threads)
310 -> decltype((void) (&loop->progress), void())
311 {
312 loop->progress.run_update_thread (*threads);
313 }
314
315
316 template <class OuterLoopType>
317 struct ThreadedLoopRunOuter { MEMALIGN(ThreadedLoopRunOuter<OuterLoopType>)
318 Iterator iterator;
319 OuterLoopType outer_loop;
320 vector<size_t> inner_axes;
321
323 template <class Functor>
324 void run_outer (Functor&& functor)
325 {
326 if (Thread::threads_to_execute() == 0) {
327 for (auto i = outer_loop (iterator); i; ++i)
328 functor (iterator);
329 return;
330 }
331
332 std::mutex mutex;
333 ProgressBar::SwitchToMultiThreaded progress_functions;
334
335 struct Shared { MEMALIGN(Shared)
336 Iterator& iterator;
337 decltype (outer_loop (iterator)) loop;
338 std::mutex& mutex;
339 FORCE_INLINE bool next (Iterator& pos) {
340 std::lock_guard<std::mutex> lock (mutex);
341 if (loop) {
342 assign_pos_of (iterator, loop.axes).to (pos);
343 ++loop;
344 return true;
345 }
346 else return false;
347 }
348 } shared = { iterator, outer_loop (iterator), mutex };
349
350 struct PerThread { MEMALIGN(PerThread)
351 Shared& shared;
352 typename std::remove_reference<Functor>::type func;
353 void execute () {
354 Iterator pos = shared.iterator;
355 while (shared.next (pos))
356 func (pos);
357 }
358 } loop_thread = { shared, functor };
359
360 auto threads = Thread::run (Thread::multi (loop_thread), "loop threads");
361
362 __manage_progress (&shared.loop, &threads);
363 threads.wait();
364 }
365
366
367
369 template <class Functor, class... ImageType>
370 void run (Functor&& functor, ImageType&&... vox)
371 {
372 ThreadedLoopRunInner<
373 sizeof...(ImageType),
374 typename std::remove_reference<Functor>::type,
375 typename std::remove_reference<ImageType>::type...
376 > loop_thread (outer_loop.axes, inner_axes, functor, vox...);
377 run_outer (loop_thread);
379 }
380
381 };
382 }
383
384
385
386
387
388
389
391 //* \sa image_thread_looping for details */
392 template <class HeaderType>
393 inline ThreadedLoopRunOuter<decltype(Loop(vector<size_t>()))>
395 const HeaderType& source,
396 const vector<size_t>& outer_axes,
397 const vector<size_t>& inner_axes)
398 { return { source, Loop (outer_axes), inner_axes }; }
399
400
402 //* \sa image_thread_looping for details */
403 template <class HeaderType>
404 inline ThreadedLoopRunOuter<decltype(Loop(vector<size_t>()))>
406 const HeaderType& source,
407 const vector<size_t>& axes,
408 size_t num_inner_axes = 1)
409 { return { source, Loop (get_outer_axes (axes, num_inner_axes)), get_inner_axes (axes, num_inner_axes) }; }
410
412 //* \sa image_thread_looping for details */
413 template <class HeaderType>
414 inline ThreadedLoopRunOuter<decltype(Loop(vector<size_t>()))>
416 const HeaderType& source,
417 size_t from_axis = 0,
418 size_t to_axis = std::numeric_limits<size_t>::max(),
419 size_t num_inner_axes = 1)
420 {
421 return { source,
422 Loop (get_outer_axes (source, num_inner_axes, from_axis, to_axis)),
423 get_inner_axes (source, num_inner_axes, from_axis, to_axis) };
424 }
425
427 //* \sa image_thread_looping for details */
428 template <class HeaderType>
429 inline ThreadedLoopRunOuter<decltype(Loop("", vector<size_t>()))>
431 const std::string& progress_message,
432 const HeaderType& source,
433 const vector<size_t>& outer_axes,
434 const vector<size_t>& inner_axes)
435 { return { source, Loop (progress_message, outer_axes), inner_axes }; }
436
438 //* \sa image_thread_looping for details */
439 template <class HeaderType>
440 inline ThreadedLoopRunOuter<decltype(Loop("", vector<size_t>()))>
442 const std::string& progress_message,
443 const HeaderType& source,
444 const vector<size_t>& axes,
445 size_t num_inner_axes = 1)
446 {
447 return { source,
448 Loop (progress_message, get_outer_axes (axes, num_inner_axes)),
449 get_inner_axes (axes, num_inner_axes) };
450 }
451
453 //* \sa image_thread_looping for details */
454 template <class HeaderType>
455 inline ThreadedLoopRunOuter<decltype(Loop("", vector<size_t>()))>
457 const std::string& progress_message,
458 const HeaderType& source,
459 size_t from_axis = 0,
460 size_t to_axis = std::numeric_limits<size_t>::max(),
461 size_t num_inner_axes = 1)
462 {
463 return { source,
464 Loop (progress_message, get_outer_axes (source, num_inner_axes, from_axis, to_axis)),
465 get_inner_axes (source, num_inner_axes, from_axis, to_axis) };
466 }
467
468
469
470}
471
472#endif
473
474
void run()
FORCE_INLINE LoopAlongAxes Loop()
Definition: loop.h:419
__run< Functor >::type run(Functor &&functor, const std::string &name="unnamed")
Execute the functor's execute method in a separate thread.
Definition: thread.h:373
size_t threads_to_execute()
__Multi< typename std::remove_reference< Functor >::type > multi(Functor &&functor, size_t nthreads=threads_to_execute())
used to request multiple threads of the corresponding functor
Definition: thread.h:285
vector< size_t > order(const HeaderType &header, size_t from_axis=0, size_t to_axis=std::numeric_limits< size_t >::max())
sort range of axes with respect to their absolute stride.
Definition: stride.h:159
Definition: base.h:24
ThreadedLoopRunOuter< decltype(Loop(vector< size_t >()))> ThreadedLoop(const HeaderType &source, const vector< size_t > &outer_axes, const vector< size_t > &inner_axes)
Multi-threaded loop object.
auto unpack(F &&f, T &&t) -> decltype(Unpack< ::std::tuple_size< typename ::std::decay< T >::type >::value >::unpack(::std::forward< F >(f), ::std::forward< T >(t)))
if t is a tuple of elements a..., invoke f(a...)
Definition: apply.h:91
void check_app_exit_code()
#define MEMALIGN(...)
Definition: types.h:185
#define FORCE_INLINE
Definition: types.h:156
vector< std::future< void > > threads
Definition: thread.h:201
std::remove_reference< Functor >::type & functor
Definition: thread.h:215