common taskscheduler: fix a potential crash issue.

Guarantee the tasks are not deleted until the taskscheduler finished them.

@Issue: https://github.com/thorvg/thorvg/issues/1370
This commit is contained in:
Hermet Park 2023-04-25 16:27:41 +09:00
parent 20466ea78f
commit ac8d0018b5
2 changed files with 43 additions and 16 deletions

View file

@ -105,7 +105,7 @@ struct TaskSchedulerImpl
uint32_t threadCnt; uint32_t threadCnt;
vector<thread> threads; vector<thread> threads;
vector<TaskQueue> taskQueues; vector<TaskQueue> taskQueues;
uint32_t idx = 0; atomic<uint32_t> idx{0};
TaskSchedulerImpl(unsigned threadCnt) : threadCnt(threadCnt), taskQueues(threadCnt) TaskSchedulerImpl(unsigned threadCnt) : threadCnt(threadCnt), taskQueues(threadCnt)
{ {

View file

@ -43,56 +43,83 @@ struct TaskScheduler
struct Task struct Task
{ {
private: private:
mutex mtx; mutex finishedMtx;
bool finished = true; mutex preparedMtx;
bool running = false; condition_variable cv;
bool finished = true; //if run() finished
bool prepared = false; //the task is requested
public: public:
virtual ~Task() = default; virtual ~Task()
{
if (!prepared) return;
//Guarantee the task is finished by TaskScheduler.
unique_lock<mutex> lock(preparedMtx);
while (prepared) {
cv.wait(lock);
}
}
void done(unsigned tid = 0) void done(unsigned tid = 0)
{ {
if (finished) return; if (finished) return;
unique_lock<mutex> lock(mtx); lock_guard<mutex> lock(finishedMtx);
if (finished) return; if (finished) return;
//the job hasn't been launched yet. //the job hasn't been launched yet.
running = true;
run(tid); //set finished so that operator() quickly returns.
running = false;
finished = true; finished = true;
run(tid);
} }
protected: protected:
virtual void run(unsigned tid) = 0; virtual void run(unsigned tid) = 0;
private: private:
void finish()
{
lock_guard<mutex> lock(preparedMtx);
prepared = false;
cv.notify_one();
}
void operator()(unsigned tid) void operator()(unsigned tid)
{ {
if (finished || running) return; if (finished) {
finish();
return;
}
lock_guard<mutex> lock(mtx); lock_guard<mutex> lock(finishedMtx);
if (finished || running) return; if (finished) {
finish();
return;
}
running = true;
run(tid); run(tid);
running = false;
finished = true; finished = true;
finish();
} }
void prepare() void prepare()
{ {
finished = false; finished = false;
prepared = true;
} }
friend struct TaskSchedulerImpl; friend struct TaskSchedulerImpl;
}; };
} }
#endif //_TVG_TASK_SCHEDULER_H_ #endif //_TVG_TASK_SCHEDULER_H_