mirror of
https://github.com/thorvg/thorvg.git
synced 2025-07-23 14:48:24 +00:00
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:
parent
20466ea78f
commit
ac8d0018b5
2 changed files with 43 additions and 16 deletions
|
@ -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)
|
||||||
{
|
{
|
||||||
|
|
|
@ -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_
|
||||||
|
|
Loading…
Add table
Reference in a new issue