Diligent Engine
Loading...
Searching...
No Matches
Diligent::IThreadPool Struct Referenceabstract

Thread pool interface. More...

#include <ThreadPool.h>

Inheritance diagram for Diligent::IThreadPool:
Diligent.IObject

Public Member Functions

virtual bool DILIGENT_CALL_TYPE EnqueueTask (IAsyncTask *pTask, IAsyncTask **ppPrerequisites=nullptr, Uint32 NumPrerequisites=0)=0
 Enqueues asynchronous task for execution.
virtual bool DILIGENT_CALL_TYPE ReprioritizeTask (IAsyncTask *pTask)=0
 Reprioritizes the task in the queue.
virtual void DILIGENT_CALL_TYPE ReprioritizeAllTasks ()=0
 Reprioritizes all tasks in the queue.
virtual bool DILIGENT_CALL_TYPE RemoveTask (IAsyncTask *pTask)=0
 Removes the task from the queue, if possible.
virtual void DILIGENT_CALL_TYPE WaitForAllTasks ()=0
 Waits until all tasks in the queue are finished.
virtual Uint32 DILIGENT_CALL_TYPE GetQueueSize ()=0
 Returns the current queue size.
virtual Uint32 DILIGENT_CALL_TYPE GetRunningTaskCount () const =0
 Returns the number of currently running tasks.
virtual void DILIGENT_CALL_TYPE StopThreads ()=0
 Stops all worker threads after draining queued tasks.
virtual bool DILIGENT_CALL_TYPE ProcessTask (Uint32 ThreadId, bool WaitForTask)=0
 Manually processes the next task from the queue.
Public Member Functions inherited from Diligent.IObject
virtual void DILIGENT_CALL_TYPE QueryInterface (const INTERFACE_ID &IID, IObject **ppInterface)=0
 Queries the specific interface.
template<typename DerivedType, typename = typename std::enable_if<std::is_base_of<IObject, DerivedType>::value>::type>
void QueryInterface (const INTERFACE_ID &IID, DerivedType **ppInterface)
virtual ReferenceCounterValueType DILIGENT_CALL_TYPE AddRef ()=0
 Increments the number of strong references by 1.
virtual ReferenceCounterValueType DILIGENT_CALL_TYPE Release ()=0
virtual IReferenceCounters *DILIGENT_CALL_TYPE GetReferenceCounters () const =0

Detailed Description

Thread pool interface.

Member Function Documentation

◆ EnqueueTask()

virtual bool DILIGENT_CALL_TYPE Diligent::IThreadPool::EnqueueTask ( IAsyncTask * pTask,
IAsyncTask ** ppPrerequisites = nullptr,
Uint32 NumPrerequisites = 0 )
pure virtual

Enqueues asynchronous task for execution.

Parameters
[in]pTask- Task to run.
[in]ppPrerequisites- Array of task prerequisites, e.g. the tasks that must be completed before this task can start.
[in]NumPrerequisites- Number of prerequisites.

Thread pool will keep a strong reference to the task, so an application is free to release it after enqueuing. A task object represents one scheduled execution and must not be enqueued again until that execution has finished or the task has been removed from the queue.

The thread pool does not keep strong references to prerequisite tasks. Prerequisites are tracked weakly; if a prerequisite object expires before this task is considered for execution, the prerequisite is treated as already satisfied.

Returns
true if the task was accepted into the queue, and false otherwise.

If this method is called after StopThreads(), an error is reported, pTask is cancelled, the task is not enqueued, and false is returned.

Note
An application must ensure that the task prerequisites are not circular to avoid deadlocks.

◆ ProcessTask()

virtual bool DILIGENT_CALL_TYPE Diligent::IThreadPool::ProcessTask ( Uint32 ThreadId,
bool WaitForTask )
pure virtual

Manually processes the next task from the queue.

Parameters
[in]ThreadId- Id of the thread that is running this task.
[in]WaitForTask- whether the function should wait for the next task:
  • if true, the function will block the thread until the next task is retrieved from the queue and processed.
  • if false, the function will return immediately if there are no tasks in the queue.
Returns
true if the thread pool is still running and the calling thread should keep processing tasks; false if the thread pool has stopped and the queue is empty.

This method allows an application to implement its own threading strategy. A thread pool may be created with zero threads, and the application may call ProcessTask() method from its own threads.

An application must keep calling the method until it returns false. If there are unhandled tasks in the queue and the application stops processing them, the thread pool will hang up.

An example of handling the tasks is shown below:

// Initialization
auto pThreadPool = CreateThreadPool(ThreadPoolCreateInfo{0});

std::vector<std::thread> WorkerThreads(4);
for (Uint32 i = 0; i < WorkerThreads.size(); ++i)
{
    WorkerThreads[i] = std::thread{
        [&ThreadPool = *pThreadPool, i] //
        {
            while (ThreadPool.ProcessTask(i, true))
            {
            }
        }};
}

// Enqueue async tasks

pThreadPool->WaitForAllTasks();

// Stop all threads in the pool
pThreadPool->StopThreads();

// Cleanup (must be done after all threads are stopped)
for (auto& Thread : WorkerThreads)
{
    Thread.join();
}

◆ RemoveTask()

virtual bool DILIGENT_CALL_TYPE Diligent::IThreadPool::RemoveTask ( IAsyncTask * pTask)
pure virtual

Removes the task from the queue, if possible.

Parameters
[in]pTask- Task to remove from the queue.
Returns
true if the task was successfully removed from the queue, and false otherwise.

If the task is found in the queue, it is marked as Diligent::ASYNC_TASK_STATUS_CANCELLED. This unblocks callers waiting in IAsyncTask::WaitForCompletion(). Running tasks are not removed; call IAsyncTask::Cancel() to request cooperative cancellation of a running task.

◆ ReprioritizeAllTasks()

virtual void DILIGENT_CALL_TYPE Diligent::IThreadPool::ReprioritizeAllTasks ( )
pure virtual

Reprioritizes all tasks in the queue.

This method should be called if task priorities have changed to update the positions of all tasks in the queue.

◆ ReprioritizeTask()

virtual bool DILIGENT_CALL_TYPE Diligent::IThreadPool::ReprioritizeTask ( IAsyncTask * pTask)
pure virtual

Reprioritizes the task in the queue.

Parameters
[in]pTask- Task to reprioritize.
Returns
true if the task was found in the queue and was successfully reprioritized, and false otherwise.

When the tasks is enqueued, its priority is used to place it in the priority queue. When an application changes the task priority, it should call this method to update the task position in the queue.

◆ StopThreads()

virtual void DILIGENT_CALL_TYPE Diligent::IThreadPool::StopThreads ( )
pure virtual

Stops all worker threads after draining queued tasks.

This method requests all worker threads to exit and blocks until they have stopped. Tasks that were already queued are processed before the threads exit, so this is a graceful drain-and-stop operation rather than an immediate cancellation of queued work.

Warning
This method must not be called from a worker thread of this pool because it joins all worker threads, including the caller.

Enqueuing tasks after calling this method is an error.

◆ WaitForAllTasks()

virtual void DILIGENT_CALL_TYPE Diligent::IThreadPool::WaitForAllTasks ( )
pure virtual

Waits until all tasks in the queue are finished.

The method blocks the calling thread until all tasks in the quque are finished and the queue is empty. An application is responsible to make sure that all tasks will finish eventually.

Warning
This method must not be called from a task running in this thread pool: the task is counted as running until it returns, while this method waits for all running tasks to finish.
Deadlock may also occur if all worker threads block waiting for work that requires those same worker threads to make progress.