Skip to content

Commit 01cb25b

Browse files
ThreadPool: fixed potential issue with the IAsyncTask::IsFinished() returning true while the task is still running
1 parent 55500db commit 01cb25b

File tree

4 files changed

+26
-17
lines changed

4 files changed

+26
-17
lines changed

Common/interface/ThreadPool.h

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -72,17 +72,20 @@ DILIGENT_BEGIN_INTERFACE(IAsyncTask, IObject)
7272

7373
/// \param [in] ThreadId - Id of the thread that is running this task.
7474
///
75-
/// \remarks This method is only called once by the thread pool.
76-
/// Before starting the task, the thread pool sets its
75+
/// \remarks Before starting the task, the thread pool sets its
7776
/// status to ASYNC_TASK_STATUS_RUNNING.
7877
///
79-
/// Before returning from the function, the task implementation must
80-
/// set the task status to either ASYNC_TASK_STATUS_CANCELLED or
81-
/// ASYNC_TASK_STATUS_COMPLETE to indicate that the task is finished,
82-
/// or to ASYNC_TASK_STATUS_NOT_STARTED to request the task to be
83-
/// rescheduled.
84-
VIRTUAL void METHOD(Run)(THIS_
85-
Uint32 ThreadId) PURE;
78+
/// The method must return one of the following values:
79+
/// - ASYNC_TASK_STATUS_CANCELLED to indicate that the task was cancelled.
80+
/// - ASYNC_TASK_STATUS_COMPLETE to indicate that the task is finished successfully.
81+
/// - ASYNC_TASK_STATUS_NOT_STARTED to request the task to be rescheduled.
82+
///
83+
/// The thread pool will set the task status to the returned value after
84+
/// the Run() method completes. This way if the GetStatus() method returns
85+
/// any value other than ASYNC_TASK_STATUS_RUNNING, it is guaranteed that the task
86+
/// is not executed by any thread.
87+
VIRTUAL ASYNC_TASK_STATUS METHOD(Run)(THIS_
88+
Uint32 ThreadId) PURE;
8689

8790
/// Cancel the task, if possible.
8891
///

Common/interface/ThreadPool.hpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,9 @@ class AsyncTaskBase : public ObjectBase<IAsyncTask>
166166
};
167167

168168

169+
/// Enqueues a function to be executed asynchronously by the thread pool.
170+
/// For the list of parameters, see Diligent::IThreadPool::EnqueueTask() method.
171+
/// The handler function must return the task status, see Diligent::IAsyncTask::Run() method.
169172
template <typename HanlderType>
170173
RefCntAutoPtr<IAsyncTask> EnqueueAsyncWork(IThreadPool* pThreadPool,
171174
IAsyncTask** ppPrerequisites,
@@ -183,12 +186,11 @@ RefCntAutoPtr<IAsyncTask> EnqueueAsyncWork(IThreadPool* pThreadPool,
183186
m_Handler{std::move(Handler)}
184187
{}
185188

186-
virtual void DILIGENT_CALL_TYPE Run(Uint32 ThreadId) override final
189+
virtual ASYNC_TASK_STATUS DILIGENT_CALL_TYPE Run(Uint32 ThreadId) override final
187190
{
188-
ASYNC_TASK_STATUS TaskStatus = !m_bSafelyCancel.load() ?
191+
return !m_bSafelyCancel.load() ?
189192
m_Handler(ThreadId) :
190193
ASYNC_TASK_STATUS_CANCELLED;
191-
SetStatus(TaskStatus);
192194
}
193195

194196
private:

Common/src/ThreadPool.cpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,11 @@ class ThreadPoolImpl final : public ObjectBase<IThreadPool>
129129
if (PrerequisitesMet)
130130
{
131131
TaskInfo.pTask->SetStatus(ASYNC_TASK_STATUS_RUNNING);
132-
TaskInfo.pTask->Run(ThreadId);
132+
ASYNC_TASK_STATUS ReturnStatus = TaskInfo.pTask->Run(ThreadId);
133+
// NB: It is essential to set the task status after the Run() method returns.
134+
// This way if the GetStatus() method returns any value other than ASYNC_TASK_STATUS_RUNNING,
135+
// it is guaranteed that the task is not executed by any thread.
136+
TaskInfo.pTask->SetStatus(ReturnStatus);
133137
TaskFinished = TaskInfo.pTask->IsFinished();
134138
DEV_CHECK_ERR((TaskFinished || TaskInfo.pTask->GetStatus() == ASYNC_TASK_STATUS_NOT_STARTED),
135139
"Finished tasks must be in COMPLETE, CANCELLED or NOT_STARTED state");

Tests/DiligentCoreTest/src/Common/ThreadPoolTest.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -173,10 +173,10 @@ class WaitTask : public AsyncTaskBase
173173
m_WaitSignal{WaitSignal}
174174
{}
175175

176-
virtual void DILIGENT_CALL_TYPE Run(Uint32 ThreadId) override final
176+
virtual ASYNC_TASK_STATUS DILIGENT_CALL_TYPE Run(Uint32 ThreadId) override final
177177
{
178178
m_WaitSignal.Wait();
179-
SetStatus(ASYNC_TASK_STATUS_COMPLETE);
179+
return ASYNC_TASK_STATUS_COMPLETE;
180180
}
181181

182182
private:
@@ -191,9 +191,9 @@ class DummyTask : public AsyncTaskBase
191191
AsyncTaskBase{pRefCounters, fPriority}
192192
{}
193193

194-
virtual void DILIGENT_CALL_TYPE Run(Uint32 ThreadId) override final
194+
virtual ASYNC_TASK_STATUS DILIGENT_CALL_TYPE Run(Uint32 ThreadId) override final
195195
{
196-
SetStatus(ASYNC_TASK_STATUS_COMPLETE);
196+
return ASYNC_TASK_STATUS_COMPLETE;
197197
}
198198
};
199199

0 commit comments

Comments
 (0)