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;
vector<thread> threads;
vector<TaskQueue> taskQueues;
uint32_t idx = 0;
atomic<uint32_t> idx{0};
TaskSchedulerImpl(unsigned threadCnt) : threadCnt(threadCnt), taskQueues(threadCnt)
{

View file

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