mirror of
https://github.com/thorvg/thorvg.git
synced 2025-07-23 06:38:43 +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;
|
||||
vector<thread> threads;
|
||||
vector<TaskQueue> taskQueues;
|
||||
uint32_t idx = 0;
|
||||
atomic<uint32_t> idx{0};
|
||||
|
||||
TaskSchedulerImpl(unsigned threadCnt) : threadCnt(threadCnt), taskQueues(threadCnt)
|
||||
{
|
||||
|
|
|
@ -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_
|
||||
|
Loading…
Add table
Reference in a new issue