| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | /* | ||
| 2 | * Copyright (c) 2000-2022 Inria | ||
| 3 | * All rights reserved. | ||
| 4 | * | ||
| 5 | * Redistribution and use in source and binary forms, with or without | ||
| 6 | * modification, are permitted provided that the following conditions are met: | ||
| 7 | * | ||
| 8 | * * Redistributions of source code must retain the above copyright notice, | ||
| 9 | * this list of conditions and the following disclaimer. | ||
| 10 | * * Redistributions in binary form must reproduce the above copyright notice, | ||
| 11 | * this list of conditions and the following disclaimer in the documentation | ||
| 12 | * and/or other materials provided with the distribution. | ||
| 13 | * * Neither the name of the ALICE Project-Team nor the names of its | ||
| 14 | * contributors may be used to endorse or promote products derived from this | ||
| 15 | * software without specific prior written permission. | ||
| 16 | * | ||
| 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
| 18 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
| 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
| 20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE | ||
| 21 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
| 22 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
| 23 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | ||
| 24 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | ||
| 25 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
| 26 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
| 27 | * POSSIBILITY OF SUCH DAMAGE. | ||
| 28 | * | ||
| 29 | * Contact: Bruno Levy | ||
| 30 | * | ||
| 31 | * https://www.inria.fr/fr/bruno-levy | ||
| 32 | * | ||
| 33 | * Inria, | ||
| 34 | * Domaine de Voluceau, | ||
| 35 | * 78150 Le Chesnay - Rocquencourt | ||
| 36 | * FRANCE | ||
| 37 | * | ||
| 38 | */ | ||
| 39 | |||
| 40 | #ifndef GEOGRAM_BASIC_PROCESS | ||
| 41 | #define GEOGRAM_BASIC_PROCESS | ||
| 42 | |||
| 43 | #include <geogram/basic/common.h> | ||
| 44 | #include <geogram/basic/thread_sync.h> | ||
| 45 | #include <geogram/basic/counted.h> | ||
| 46 | #include <geogram/basic/smart_pointer.h> | ||
| 47 | #include <functional> | ||
| 48 | |||
| 49 | /** | ||
| 50 | * \file geogram/basic/process.h | ||
| 51 | * \brief Function and classes for process manipulation | ||
| 52 | */ | ||
| 53 | |||
| 54 | namespace GEO { | ||
| 55 | |||
| 56 | /** | ||
| 57 | * \brief Platform-independent base class for running threads. | ||
| 58 | * \details | ||
| 59 | * A Thread object manages one thread of control within the program. | ||
| 60 | * Thread%s begin executing with run(). Operational threads can be created | ||
| 61 | * by creating a derived class and reimplement function run(). | ||
| 62 | * | ||
| 63 | * Thread%s are reference-counted objects. Their allocation and | ||
| 64 | * destruction can be automatically managed with Thread_var. | ||
| 65 | */ | ||
| 66 | class GEOGRAM_API Thread : public Counted { | ||
| 67 | public: | ||
| 68 | |||
| 69 | /** | ||
| 70 | * \brief Thread constructor. | ||
| 71 | */ | ||
| 72 | 12208 | Thread() : id_(0) { | |
| 73 | 12208 | } | |
| 74 | |||
| 75 | /** | ||
| 76 | * \brief Starts the thread execution. | ||
| 77 | */ | ||
| 78 | virtual void run() = 0; | ||
| 79 | |||
| 80 | /** | ||
| 81 | * \brief Gets the identifier of this thread. | ||
| 82 | * \return the identifier of the thread, i.e. | ||
| 83 | * an unsigned integer in the range [0, N-1] | ||
| 84 | * where N denotes the number of currently | ||
| 85 | * running threads. | ||
| 86 | */ | ||
| 87 | 3963074 | index_t id() const { | |
| 88 | 3963074 | return id_; | |
| 89 | } | ||
| 90 | |||
| 91 | /** | ||
| 92 | * \brief Gets the current thread. | ||
| 93 | * \return A pointer to the instance of the | ||
| 94 | * currently running thread. If not running multiple | ||
| 95 | * threads, returns nullptr. | ||
| 96 | */ | ||
| 97 | static Thread* current(); | ||
| 98 | |||
| 99 | /** | ||
| 100 | * \brief Gets the identifier of the current thread. | ||
| 101 | * \return the identifier of the current thread, i.e. | ||
| 102 | * an unsigned integer in the range [0, N-1] | ||
| 103 | * where N denotes the number of currently | ||
| 104 | * running threads. If not running multiple threads, | ||
| 105 | * returns 0. | ||
| 106 | */ | ||
| 107 | 2417 | static index_t current_id() { | |
| 108 |
2/2✓ Branch 1 taken 2406 times.
✓ Branch 2 taken 11 times.
|
2417 | return current() == nullptr ? 0 : current()->id(); |
| 109 | } | ||
| 110 | |||
| 111 | protected: | ||
| 112 | /** Thread destructor */ | ||
| 113 | ~Thread() override; | ||
| 114 | |||
| 115 | |||
| 116 | private: | ||
| 117 | /** | ||
| 118 | * \brief Sets the identifier of this thread. | ||
| 119 | * \details This function is meant to be called | ||
| 120 | * by the thread manager for each created thread. | ||
| 121 | * \param[in] id_in the identifier of this thread. | ||
| 122 | */ | ||
| 123 | 12200 | void set_id(index_t id_in) { | |
| 124 | 12200 | id_ = id_in; | |
| 125 | 12200 | } | |
| 126 | |||
| 127 | /** | ||
| 128 | * \brief Specifies the current instance, used by current(). | ||
| 129 | * \details Stores the specified thread in the thread-local-storage | ||
| 130 | * static variable so that current() can retrieve it. | ||
| 131 | * Should be called by the ThreadManager right before launching | ||
| 132 | * the threads. | ||
| 133 | * \param[in] thread a pointer to the thread currently executed | ||
| 134 | */ | ||
| 135 | static void set_current(Thread* thread); | ||
| 136 | |||
| 137 | index_t id_; | ||
| 138 | |||
| 139 | // ThreadManager needs to access set_current() and | ||
| 140 | // set_id(). | ||
| 141 | friend class ThreadManager; | ||
| 142 | }; | ||
| 143 | |||
| 144 | /** Smart pointer that contains a Thread object */ | ||
| 145 | typedef SmartPointer<Thread> Thread_var; | ||
| 146 | |||
| 147 | /** | ||
| 148 | * \brief Collection of Thread%s | ||
| 149 | * \details ThreadGroup is a std::vector of Thread_var it provides the | ||
| 150 | * same operations for adding, removing or accessing thread elements. | ||
| 151 | * ThreadGroup takes ownership of Thread elements when they are added to | ||
| 152 | * the group, so there's is no need to delete Threads when the group is | ||
| 153 | * deleted. | ||
| 154 | */ | ||
| 155 | typedef std::vector<Thread_var> ThreadGroup; | ||
| 156 | |||
| 157 | /** | ||
| 158 | * \brief Typed collection of Thread%s. | ||
| 159 | * \details | ||
| 160 | * TypedThreadGroup is a ThreadGroup that provides a typed accessor with | ||
| 161 | * operator[](). | ||
| 162 | * \tparam THREAD the type of Thread%s in the collection | ||
| 163 | */ | ||
| 164 | template <class THREAD> | ||
| 165 | class TypedThreadGroup : public ThreadGroup { | ||
| 166 | public: | ||
| 167 | /** | ||
| 168 | * \brief Creates an empty group of Thread%s | ||
| 169 | * \details Thread elements can be added with the std::vector | ||
| 170 | * operation push_back() | ||
| 171 | */ | ||
| 172 | 34 | TypedThreadGroup() { | |
| 173 | 34 | } | |
| 174 | |||
| 175 | /** | ||
| 176 | * \brief Gets a thread element by index | ||
| 177 | * \param[in] i index of the element | ||
| 178 | * \return a pointer to the \p THREAD at position \p i in the | ||
| 179 | * thread group | ||
| 180 | */ | ||
| 181 | 180 | THREAD* operator[] (index_t i) { | |
| 182 |
1/6✗ Branch 1 not taken.
✓ Branch 2 taken 180 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
|
180 | geo_debug_assert(i < size()); |
| 183 | 180 | Thread* result = ThreadGroup::operator[] (i); | |
| 184 | 180 | return static_cast<THREAD*>(result); | |
| 185 | } | ||
| 186 | }; | ||
| 187 | |||
| 188 | /** | ||
| 189 | * \brief Platform-independent base class for running concurrent threads. | ||
| 190 | * \details | ||
| 191 | * The ThreadManager manager provides a platform-independent abstract | ||
| 192 | * interface for running concurrent Threads and managing critical | ||
| 193 | * sections. | ||
| 194 | * | ||
| 195 | * The ThreadManager is derived in multiple platform-specific or | ||
| 196 | * technology-specific implementations. | ||
| 197 | * | ||
| 198 | * Platform-specific implementations: | ||
| 199 | * - POSIX Thread manager (Unix) | ||
| 200 | * - Windows Threads manager (Windows) | ||
| 201 | * - Windows ThreadPool manager (Windows) | ||
| 202 | * | ||
| 203 | * Technology-specific implementations: | ||
| 204 | * - OpenMP-based manager | ||
| 205 | * | ||
| 206 | * Which ThreadManager to use is determined at runtime by | ||
| 207 | * Process::initialize() according to the current platform or the current | ||
| 208 | * available technology. | ||
| 209 | * | ||
| 210 | * \note For internal use only. | ||
| 211 | * \see Process::set_thread_manager() | ||
| 212 | */ | ||
| 213 | class GEOGRAM_API ThreadManager : public Counted { | ||
| 214 | public: | ||
| 215 | /** | ||
| 216 | * \brief Runs a group of Thread%s. | ||
| 217 | * \details | ||
| 218 | * This start the execution of the threads | ||
| 219 | * contained in vector \p threads. | ||
| 220 | * | ||
| 221 | * If the threads cannot be executed in a concurrent environment | ||
| 222 | * (multi-threading is disabled or the number of maximum threads is 1), | ||
| 223 | * then the threads are executed sequentially. Otherwise the function | ||
| 224 | * run_concurrent_threads() is called to execute the threads | ||
| 225 | * concurrently. The execution terminates when the last thread | ||
| 226 | * terminates. | ||
| 227 | * | ||
| 228 | * \param[in] threads the vector of threads to be executed. | ||
| 229 | * \see maximum_concurrent_threads() | ||
| 230 | * \see run_concurrent_threads() | ||
| 231 | * \see Process::max_threads() | ||
| 232 | */ | ||
| 233 | virtual void run_threads(ThreadGroup& threads); | ||
| 234 | |||
| 235 | /** | ||
| 236 | * \brief Gets the maximum number of possible concurrent threads | ||
| 237 | * \return The maximum number of possible concurrent threads allowed | ||
| 238 | * by this manager. It depends on the physical number of cores | ||
| 239 | * (including hyper-threading or not) and the technology implemented | ||
| 240 | * by this manager. | ||
| 241 | * \see Process::number_of_cores() | ||
| 242 | */ | ||
| 243 | virtual index_t maximum_concurrent_threads() = 0; | ||
| 244 | |||
| 245 | protected: | ||
| 246 | /** | ||
| 247 | * \brief Runs a group of Thread%s concurrently. | ||
| 248 | * \details This start the concurrent execution of the threads | ||
| 249 | * contained in vector \p threads, using the given number of threads | ||
| 250 | * \p max_threads. The execution terminates when the last thread | ||
| 251 | * terminates. | ||
| 252 | * \param[in] threads the vector of threads to be executed. | ||
| 253 | * \param[in] max_threads maximum number of threads allowed for this | ||
| 254 | * execution. It is always greater than one | ||
| 255 | */ | ||
| 256 | virtual void run_concurrent_threads( | ||
| 257 | ThreadGroup& threads, index_t max_threads | ||
| 258 | ) = 0; | ||
| 259 | |||
| 260 | |||
| 261 | /** | ||
| 262 | * \brief Sets the id of a thread. | ||
| 263 | * \details This function is called right before starting | ||
| 264 | * the threads. Each thread will have an id in [0, N-1] | ||
| 265 | * where N denotes the number of running threads. | ||
| 266 | * \param[in] thread the thread | ||
| 267 | * \param[in] id the id | ||
| 268 | */ | ||
| 269 | 12200 | static void set_thread_id(Thread* thread, index_t id) { | |
| 270 | 12200 | thread->set_id(id); | |
| 271 | 12200 | } | |
| 272 | |||
| 273 | /** | ||
| 274 | * \brief Specifies the current instance, used by current(). | ||
| 275 | * \details Stores the specified thread in the thread-local-storage | ||
| 276 | * static variable so that current() can retrieve it. | ||
| 277 | * Should be called by the ThreadManager right before launching | ||
| 278 | * the threads. | ||
| 279 | * \param[in] thread a pointer to the thread currently executed | ||
| 280 | */ | ||
| 281 | 12200 | static void set_current_thread(Thread* thread) { | |
| 282 | 12200 | Thread::set_current(thread); | |
| 283 | 12200 | } | |
| 284 | |||
| 285 | /** ThreadManager destructor */ | ||
| 286 | ~ThreadManager() override; | ||
| 287 | }; | ||
| 288 | |||
| 289 | /** Smart pointer that contains a ThreadManager object */ | ||
| 290 | typedef SmartPointer<ThreadManager> ThreadManager_var; | ||
| 291 | |||
| 292 | /** | ||
| 293 | * \brief Single thread ThreadManager | ||
| 294 | * \details MonoThreadingThreadManager implements a ThreadManager for | ||
| 295 | * single thread environments. | ||
| 296 | */ | ||
| 297 | class GEOGRAM_API MonoThreadingThreadManager : public ThreadManager { | ||
| 298 | public: | ||
| 299 | /** | ||
| 300 | * \copydoc ThreadManager::maximum_concurrent_threads() | ||
| 301 | * \note This implementation always returns 1. | ||
| 302 | */ | ||
| 303 | index_t maximum_concurrent_threads() override; | ||
| 304 | |||
| 305 | protected: | ||
| 306 | /** MonoThreadingThreadManager destructor */ | ||
| 307 | ~MonoThreadingThreadManager() override; | ||
| 308 | |||
| 309 | /** | ||
| 310 | * \copydoc ThreadManager::run_concurrent_threads() | ||
| 311 | * \note This implementation always executes threads sequentially. | ||
| 312 | */ | ||
| 313 | void run_concurrent_threads( | ||
| 314 | ThreadGroup& threads, index_t max_threads | ||
| 315 | ) override; | ||
| 316 | }; | ||
| 317 | |||
| 318 | /** | ||
| 319 | * \brief Abstraction layer for process management and multi-threading. | ||
| 320 | */ | ||
| 321 | namespace Process { | ||
| 322 | |||
| 323 | /** | ||
| 324 | * \brief Initializes GeogramLib | ||
| 325 | * \param[in] flags the flags passed to GEO::initialize() | ||
| 326 | * \details This function must be called once before using | ||
| 327 | * any functionality of GeogramLib. | ||
| 328 | */ | ||
| 329 | void GEOGRAM_API initialize(int flags); | ||
| 330 | |||
| 331 | /** | ||
| 332 | * \brief Terminates GeogramLib | ||
| 333 | * \details This function is called automatically when the program | ||
| 334 | * exits, so it should never be called directly. | ||
| 335 | */ | ||
| 336 | void GEOGRAM_API terminate(); | ||
| 337 | |||
| 338 | |||
| 339 | /** | ||
| 340 | * \brief Sleeps for a period of time. | ||
| 341 | * \param[in] microseconds the time to sleep, | ||
| 342 | * in microseconds. | ||
| 343 | */ | ||
| 344 | void GEOGRAM_API sleep(index_t microseconds); | ||
| 345 | |||
| 346 | /** | ||
| 347 | * \brief Displays statistics about the current process | ||
| 348 | * \details Displays the maximum used amount of memory. | ||
| 349 | */ | ||
| 350 | void GEOGRAM_API show_stats(); | ||
| 351 | |||
| 352 | /** | ||
| 353 | * \brief Terminates the current process. | ||
| 354 | */ | ||
| 355 | void GEOGRAM_API brute_force_kill(); | ||
| 356 | |||
| 357 | /** | ||
| 358 | * \brief Returns the maximum number of threads that can be running | ||
| 359 | * simultaneously. | ||
| 360 | * \retval The number of cores if multi-threading is supported | ||
| 361 | * \retval 1 otherwise. | ||
| 362 | */ | ||
| 363 | index_t GEOGRAM_API maximum_concurrent_threads(); | ||
| 364 | |||
| 365 | /** | ||
| 366 | * \brief Runs a set of threads simultaneously | ||
| 367 | * \details Launches the execution of the threads contained in the | ||
| 368 | * vector \p threads and waits for the completion of all of them. | ||
| 369 | */ | ||
| 370 | void GEOGRAM_API run_threads(ThreadGroup& threads); | ||
| 371 | |||
| 372 | /** | ||
| 373 | * \brief Gets the number of available cores | ||
| 374 | * \return The number of available cores including the "virtual ones" if | ||
| 375 | * hyper-threading is activated. | ||
| 376 | */ | ||
| 377 | index_t GEOGRAM_API number_of_cores(); | ||
| 378 | |||
| 379 | /** | ||
| 380 | * \brief Sets the thread manager (internal use). | ||
| 381 | * \details This sets the ThreadManager to use for concurrent thread | ||
| 382 | * execution. This function is called internally by | ||
| 383 | * Process::initialize() and should not be called explicitly. | ||
| 384 | * \note For internal use only | ||
| 385 | */ | ||
| 386 | void GEOGRAM_API set_thread_manager(ThreadManager* thread_manager); | ||
| 387 | |||
| 388 | /** | ||
| 389 | * \brief Checks whether threads are running. | ||
| 390 | * \retval true if concurrent threads are currently running as an | ||
| 391 | * effect to Process::run_threads(). | ||
| 392 | * \retval false otherwise. | ||
| 393 | * \see Process::run_threads() | ||
| 394 | */ | ||
| 395 | bool GEOGRAM_API is_running_threads(); | ||
| 396 | |||
| 397 | /** | ||
| 398 | * \brief Enables/disables floating point exceptions | ||
| 399 | * \details If FPEs are enabled, then floating point exceptions | ||
| 400 | * raise a SIGFPE signal, otherwise they generate NaNs. FPEs can also | ||
| 401 | * be configured by setting the value of the property "sys:FPE" with | ||
| 402 | * Environment::set_value(). | ||
| 403 | * \param[in] flag set to \c true to enable FPEs, \c false to disable. | ||
| 404 | * \see FPE_enabled() | ||
| 405 | */ | ||
| 406 | void GEOGRAM_API enable_FPE(bool flag); | ||
| 407 | |||
| 408 | /** | ||
| 409 | * \brief Gets the status of floating point exceptions | ||
| 410 | * \retval true if FPE are enabled | ||
| 411 | * \retval false otherwise | ||
| 412 | * \see enable_FPE() | ||
| 413 | */ | ||
| 414 | bool GEOGRAM_API FPE_enabled(); | ||
| 415 | |||
| 416 | /** | ||
| 417 | * \brief Enables/disables multi-threaded computations | ||
| 418 | * Multi-threading can also be configured by setting the value of the | ||
| 419 | * property "sys:multithread" with Environment::set_value(). | ||
| 420 | * \param[in] flag set to \c true to enable multi-threading, \c false | ||
| 421 | * to disable. | ||
| 422 | * \see multithreading_enabled() | ||
| 423 | */ | ||
| 424 | void GEOGRAM_API enable_multithreading(bool flag); | ||
| 425 | |||
| 426 | /** | ||
| 427 | * \brief Gets the status of multi-threading | ||
| 428 | * \retval true if multi-threading is enabled | ||
| 429 | * \retval false otherwise | ||
| 430 | * \see enable_multithreading() | ||
| 431 | */ | ||
| 432 | bool GEOGRAM_API multithreading_enabled(); | ||
| 433 | |||
| 434 | /** | ||
| 435 | * \brief Limits the number of concurrent threads to use | ||
| 436 | * \details The number of threads can also be configured by setting | ||
| 437 | * the value of the property "sys:max_threads" with | ||
| 438 | * Environment::set_value(). | ||
| 439 | * \param[in] num_threads maximum number of threads to use. | ||
| 440 | * \see max_threads() | ||
| 441 | */ | ||
| 442 | void GEOGRAM_API set_max_threads(index_t num_threads); | ||
| 443 | |||
| 444 | /** | ||
| 445 | * \brief Gets the number of allowed concurrent threads | ||
| 446 | * \see set_max_threads() | ||
| 447 | */ | ||
| 448 | index_t GEOGRAM_API max_threads(); | ||
| 449 | |||
| 450 | /** | ||
| 451 | * \brief Enables interruption of cancelable tasks | ||
| 452 | * \details This allows to interrupt cancelable tasks by typing | ||
| 453 | * CTRL-C in the terminal. This sets a specific handler on the | ||
| 454 | * interrupt signal that calls Progress::cancel() is there is a | ||
| 455 | * running cancelable task. If no task is running, the program is | ||
| 456 | * interrupted. The cancel mode can also be configured by setting the | ||
| 457 | * value of the property "sys:cancel" with | ||
| 458 | * Environment::set_value(). | ||
| 459 | * \param[in] flag set to \c true to enable cancel mode, \c false | ||
| 460 | * to disable. | ||
| 461 | * \see cancel_enabled() | ||
| 462 | */ | ||
| 463 | void GEOGRAM_API enable_cancel(bool flag); | ||
| 464 | |||
| 465 | /** | ||
| 466 | * \brief Gets the status of the cancel mode | ||
| 467 | * \retval true if the cancel mode is enabled | ||
| 468 | * \retval false otherwise | ||
| 469 | * \see enable_cancel() | ||
| 470 | */ | ||
| 471 | bool GEOGRAM_API cancel_enabled(); | ||
| 472 | |||
| 473 | /** | ||
| 474 | * \brief Gets the currently used memory. | ||
| 475 | * \return the used memory in bytes | ||
| 476 | */ | ||
| 477 | size_t GEOGRAM_API used_memory(); | ||
| 478 | |||
| 479 | /** | ||
| 480 | * \brief Gets the maximum used memory. | ||
| 481 | * \return the maximum used memory in bytes | ||
| 482 | */ | ||
| 483 | size_t GEOGRAM_API max_used_memory(); | ||
| 484 | |||
| 485 | /** | ||
| 486 | * \brief Gets the full path to the currently | ||
| 487 | * running program. | ||
| 488 | */ | ||
| 489 | std::string GEOGRAM_API executable_filename(); | ||
| 490 | |||
| 491 | /** | ||
| 492 | * \brief Prints a stack trace to the standard error. | ||
| 493 | */ | ||
| 494 | void print_stack_trace(); | ||
| 495 | } | ||
| 496 | |||
| 497 | /** | ||
| 498 | * \brief Executes a loop with concurrent threads. | ||
| 499 | * \details | ||
| 500 | * Executes a parallel for loop from index \p to index \p to, calling | ||
| 501 | * functional object \p func at each iteration. | ||
| 502 | * | ||
| 503 | * Calling parallel_for(from, to, func) is equivalent | ||
| 504 | * to the following loop, computed in parallel: | ||
| 505 | * \code | ||
| 506 | * for(index_t i = from; i < to; i++) { | ||
| 507 | * func(i) | ||
| 508 | * } | ||
| 509 | * \endcode | ||
| 510 | * | ||
| 511 | * When applicable, iterations are executed by concurrent threads: | ||
| 512 | * the range of the loop is split in to several contiguous | ||
| 513 | * sub-ranges, each of them being executed by a separate thread. | ||
| 514 | * | ||
| 515 | * If parameter \p interleaved is set to true, the loop range is | ||
| 516 | * decomposed in interleaved index sets. Interleaved execution may | ||
| 517 | * improve cache coherency. | ||
| 518 | * | ||
| 519 | * \param[in] func function that takes an index_t. | ||
| 520 | * \param[in] from the first iteration index | ||
| 521 | * \param[in] to one position past the last iteration index | ||
| 522 | * \param[in] threads_per_core number of threads to allocate per physical | ||
| 523 | * core (default is 1). | ||
| 524 | * \param[in] interleaved if set to \c true, indices are allocated to | ||
| 525 | * threads with an interleaved pattern. | ||
| 526 | */ | ||
| 527 | void GEOGRAM_API parallel_for( | ||
| 528 | index_t from, index_t to, std::function<void(index_t)> func, | ||
| 529 | index_t threads_per_core = 1, | ||
| 530 | bool interleaved = false | ||
| 531 | ); | ||
| 532 | |||
| 533 | /** | ||
| 534 | * \brief Executes a loop with concurrent threads. | ||
| 535 | * | ||
| 536 | * \details | ||
| 537 | * When applicable, iterations are executed by concurrent | ||
| 538 | * threads: the range of the loop is split in to several contiguous | ||
| 539 | * sub-ranges, each of them being executed by a separate thread. | ||
| 540 | * | ||
| 541 | * Calling parallel_for(func, from, to) is equivalent | ||
| 542 | * to the following loop, computed in parallel: | ||
| 543 | * \code | ||
| 544 | * func(from, i1); | ||
| 545 | * func(i1, i2); | ||
| 546 | * ... | ||
| 547 | * func(in, to); | ||
| 548 | * \endcode | ||
| 549 | * where i1,i2,...in are automatically generated. Typically one interval | ||
| 550 | * per physical core is generated. | ||
| 551 | * | ||
| 552 | * \param[in] func functional object that accepts two arguments of | ||
| 553 | * type index_t. | ||
| 554 | * \param[in] from first iteration index of the loop | ||
| 555 | * \param[in] to one position past the last iteration index | ||
| 556 | * \param[in] threads_per_core number of threads to allocate per physical | ||
| 557 | * core (default is 1). | ||
| 558 | */ | ||
| 559 | void GEOGRAM_API parallel_for_slice( | ||
| 560 | index_t from, index_t to, std::function<void(index_t, index_t)> func, | ||
| 561 | index_t threads_per_core = 1 | ||
| 562 | ); | ||
| 563 | |||
| 564 | /** | ||
| 565 | * \brief Calls functions in parallel. | ||
| 566 | * \details Can be typically used with lambdas that capture this. See | ||
| 567 | * mesh/mesh_reorder.cpp and points/kd_tree.cpp for examples. | ||
| 568 | * \param[in] f1 , f2 functions to be called in parallel. | ||
| 569 | */ | ||
| 570 | void GEOGRAM_API parallel( | ||
| 571 | std::function<void()> f1, | ||
| 572 | std::function<void()> f2 | ||
| 573 | ); | ||
| 574 | |||
| 575 | /** | ||
| 576 | * \brief Calls functions in parallel. | ||
| 577 | * \details Can be typically used with lambdas that capture this. See | ||
| 578 | * mesh/mesh_reorder.cpp and points/kd_tree.cpp for examples. | ||
| 579 | * \param[in] f1 , f2 , f3 , f4 functions to be called in parallel. | ||
| 580 | */ | ||
| 581 | void GEOGRAM_API parallel( | ||
| 582 | std::function<void()> f1, | ||
| 583 | std::function<void()> f2, | ||
| 584 | std::function<void()> f3, | ||
| 585 | std::function<void()> f4 | ||
| 586 | ); | ||
| 587 | |||
| 588 | /** | ||
| 589 | * \brief Calls functions in parallel. | ||
| 590 | * \details Can be typically used with lambdas that capture this. See | ||
| 591 | * mesh/mesh_reorder.cpp and points/kd_tree.cpp for examples. | ||
| 592 | * \param[in] f1 , f2 , f3 , f4 , f5 , f6 , f7 , f8 functions | ||
| 593 | * to be called in parallel. | ||
| 594 | */ | ||
| 595 | void GEOGRAM_API parallel( | ||
| 596 | std::function<void()> f1, | ||
| 597 | std::function<void()> f2, | ||
| 598 | std::function<void()> f3, | ||
| 599 | std::function<void()> f4, | ||
| 600 | std::function<void()> f5, | ||
| 601 | std::function<void()> f6, | ||
| 602 | std::function<void()> f7, | ||
| 603 | std::function<void()> f8 | ||
| 604 | ); | ||
| 605 | |||
| 606 | } | ||
| 607 | |||
| 608 | #endif | ||
| 609 |