#pragma region CPL License /* Nuclex Native Framework Copyright (C) 2002-2023 Nuclex Development Labs This library is free software; you can redistribute it and/or modify it under the terms of the IBM Common Public License as published by the IBM Corporation; either version 1.0 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the IBM Common Public License for more details. You should have received a copy of the IBM Common Public License along with this library */ #pragma endregion // CPL License #ifndef NUCLEX_PLATFORM_TASKS_THREADEDTASK_H #define NUCLEX_PLATFORM_TASKS_THREADEDTASK_H #include "Nuclex/Platform/Config.h" #include "Nuclex/Platform/Tasks/Task.h" // for Task namespace Nuclex { namespace Support { namespace Threading { // ------------------------------------------------------------------------------------------- // class ThreadPool; // ------------------------------------------------------------------------------------------- // }}} // namespace Nuclex::Support::Threading namespace Nuclex { namespace Platform { namespace Tasks { // ------------------------------------------------------------------------------------------- // /// Task that uses multiple threads via the thread pool /// /// /// Use this class if you create tasks that perform work on multiple threads by /// themselves (if, instead, you have a third party library that does its own /// threading, use normal task and just set the resource manifest to the number /// of CPU cores that the third-party library will use). /// /// /// Your RunThreaded() method will be called on the number of threads you specify. /// /// class NUCLEX_PLATFORM_TYPE ThreadedTask : public Task { /// Initializes a threaded task using the specified number of threads /// Thread pool that will run the task's workload /// /// Maximum number of threads to use. This is the number of calls that will be made /// to the method. If the thread pool has fewer threads than /// this number, then some of the calls will happen /// sequentially on reused threadpool threads, which may lead to poor CPU utilization /// (i.e. threaded task with 6 intended threads on 4 core CPU will keep 4 cores busy /// for a bit, then run the remaining 2 task threads and keep only 2 cores busy). /// public: NUCLEX_PLATFORM_API ThreadedTask( Nuclex::Support::Threading::ThreadPool &threadPool, std::size_t maximumThreadCount = std::size_t(-1) ) : threadPool(threadPool), maximumThreadCount(maximumThreadCount) {} /// Frees all resources owned by the task /// /// The task must be either finished or cancelled before it may be destroyed. /// public: NUCLEX_PLATFORM_API virtual ~ThreadedTask() = default; /// Executes the task, using the specified resource units /// /// Indices of the resource units the task coordinator has assigned this task /// /// /// Lets the task detect when it is requested to cancel its processing /// public: NUCLEX_PLATFORM_API void Run( const std::array &resourceUnitIndices, const CancellationWatcher &cancellationWatcher ) noexcept override; /// /// Called in parallel on the specified number of threads to perform the task's work /// /// /// when you set up the task coordinator, you specify one or more "units" /// that provide each resources (likely you'll only add one "SystemMemory" /// unit but there may be one "VideoMemory" unit per GPU in the system). /// This array tells your task which resource units the task coordinator wants it /// to use. Feel free to ignore this if you only ever have one unit of each resource. /// /// /// Can be used to figure out whether the task has been cancelled. This will happen /// if the task coordinator is shut down or cleared while tasks are executing. /// Any task that takes longer than a couple of milliseconds should check for /// cancellation at regular intervals to ensure the task coordinator isn't clogged. /// protected: NUCLEX_PLATFORM_API virtual void ThreadedRun( const std::array &resourceUnitIndices, const CancellationWatcher &cancellationWatcher ) noexcept = 0; /// /// Used internally to calls the ThreadedRun() method the a thread pool thread /// /// The 'this' pointer of the threaded task instance /// /// Indices of the resource units the task coordinator has assigned this task /// /// /// Lets the task detect when it is requested to cancel its processing /// /// /// This method is used rather than std::bind() in order to not pollute the call stack /// and avoid the use of needless lambda functors in the thread pool callbacks. /// private: static void invokeThreadedRun( ThreadedTask *self, const std::array *resourceUnitIndices, const CancellationWatcher *cancellationWatcher ); /// Thread pool that will be used to run work in multiple threads private: Nuclex::Support::Threading::ThreadPool &threadPool; /// Maximum number of threads that the task will use private: std::size_t maximumThreadCount; }; // ------------------------------------------------------------------------------------------- // }}} // namespace Nuclex::Platform::Tasks #endif // NUCLEX_PLATFORM_TASKS_THREADEDTASK_H