Linkgraph: Allow job threads to be aborted early when clearing schedule.
This commit is contained in:
@@ -50,7 +50,8 @@ LinkGraphJob::LinkGraphJob(const LinkGraph &orig, uint duration_multiplier) :
|
|||||||
settings(_settings_game.linkgraph),
|
settings(_settings_game.linkgraph),
|
||||||
join_date_ticks(GetLinkGraphJobJoinDateTicks(duration_multiplier)),
|
join_date_ticks(GetLinkGraphJobJoinDateTicks(duration_multiplier)),
|
||||||
start_date_ticks((_date * DAY_TICKS) + _date_fract),
|
start_date_ticks((_date * DAY_TICKS) + _date_fract),
|
||||||
job_completed(false)
|
job_completed(false),
|
||||||
|
abort_job(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -184,6 +185,41 @@ bool LinkGraphJob::IsJobCompleted() const
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if job has been requested to be aborted.
|
||||||
|
* This is allowed to spuriously return a falsely negative value.
|
||||||
|
* @return True if job abort has been requested.
|
||||||
|
*/
|
||||||
|
bool LinkGraphJob::IsJobAborted() const
|
||||||
|
{
|
||||||
|
#if defined(__GNUC__) || defined(__clang__)
|
||||||
|
return __atomic_load_n(&abort_job, __ATOMIC_RELAXED);
|
||||||
|
#else
|
||||||
|
return abort_job;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abort job.
|
||||||
|
* The job may exit early at the next available opportunity.
|
||||||
|
* After this method has been called the state of the job is undefined, and the only valid operation
|
||||||
|
* is to join the thread and discard the job data.
|
||||||
|
*/
|
||||||
|
void LinkGraphJob::AbortJob()
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Note that this it not guaranteed to be an atomic write and there are no memory barriers or other protections.
|
||||||
|
* Readers of this variable in another thread may see an out of date value.
|
||||||
|
* However this is OK as if this method is called the state of the job/thread does not matter anyway.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if defined(__GNUC__) || defined(__clang__)
|
||||||
|
__atomic_store_n(&(abort_job), true, __ATOMIC_RELAXED);
|
||||||
|
#else
|
||||||
|
abort_job = true;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize the link graph job: Resize nodes and edges and populate them.
|
* Initialize the link graph job: Resize nodes and edges and populate them.
|
||||||
* This is done after the constructor so that we can do it in the calculation
|
* This is done after the constructor so that we can do it in the calculation
|
||||||
|
@@ -69,10 +69,12 @@ protected:
|
|||||||
NodeAnnotationVector nodes; ///< Extra node data necessary for link graph calculation.
|
NodeAnnotationVector nodes; ///< Extra node data necessary for link graph calculation.
|
||||||
EdgeAnnotationMatrix edges; ///< Extra edge data necessary for link graph calculation.
|
EdgeAnnotationMatrix edges; ///< Extra edge data necessary for link graph calculation.
|
||||||
bool job_completed; ///< Is the job still running. This is accessed by multiple threads and is permitted to be spuriously incorrect.
|
bool job_completed; ///< Is the job still running. This is accessed by multiple threads and is permitted to be spuriously incorrect.
|
||||||
|
bool abort_job; ///< Abort the job at the next available opportunity. This is accessed by multiple threads.
|
||||||
|
|
||||||
void EraseFlows(NodeID from);
|
void EraseFlows(NodeID from);
|
||||||
void JoinThread();
|
void JoinThread();
|
||||||
void SetJobGroup(std::shared_ptr<LinkGraphJobGroup> group);
|
void SetJobGroup(std::shared_ptr<LinkGraphJobGroup> group);
|
||||||
|
bool IsJobAborted() const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
@@ -282,6 +284,7 @@ public:
|
|||||||
void FinaliseJob();
|
void FinaliseJob();
|
||||||
|
|
||||||
bool IsJobCompleted() const;
|
bool IsJobCompleted() const;
|
||||||
|
void AbortJob();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if job is supposed to be finished.
|
* Check if job is supposed to be finished.
|
||||||
|
@@ -130,6 +130,7 @@ void LinkGraphSchedule::JoinNext()
|
|||||||
this->running.pop_front();
|
this->running.pop_front();
|
||||||
LinkGraphID id = next->LinkGraphIndex();
|
LinkGraphID id = next->LinkGraphIndex();
|
||||||
next->FinaliseJob(); // joins the thread and finalises the job
|
next->FinaliseJob(); // joins the thread and finalises the job
|
||||||
|
assert(!next->IsJobAborted());
|
||||||
next.reset();
|
next.reset();
|
||||||
if (LinkGraph::IsValidID(id)) {
|
if (LinkGraph::IsValidID(id)) {
|
||||||
LinkGraph *lg = LinkGraph::Get(id);
|
LinkGraph *lg = LinkGraph::Get(id);
|
||||||
@@ -148,6 +149,7 @@ void LinkGraphSchedule::JoinNext()
|
|||||||
{
|
{
|
||||||
LinkGraphJob *job = (LinkGraphJob *)j;
|
LinkGraphJob *job = (LinkGraphJob *)j;
|
||||||
for (uint i = 0; i < lengthof(instance.handlers); ++i) {
|
for (uint i = 0; i < lengthof(instance.handlers); ++i) {
|
||||||
|
if (job->IsJobAborted()) return;
|
||||||
instance.handlers[i]->Run(*job);
|
instance.handlers[i]->Run(*job);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -186,7 +188,7 @@ void LinkGraphSchedule::SpawnAll()
|
|||||||
/* static */ void LinkGraphSchedule::Clear()
|
/* static */ void LinkGraphSchedule::Clear()
|
||||||
{
|
{
|
||||||
for (JobList::iterator i(instance.running.begin()); i != instance.running.end(); ++i) {
|
for (JobList::iterator i(instance.running.begin()); i != instance.running.end(); ++i) {
|
||||||
(*i)->JoinThread();
|
(*i)->AbortJob();
|
||||||
}
|
}
|
||||||
instance.running.clear();
|
instance.running.clear();
|
||||||
instance.schedule.clear();
|
instance.schedule.clear();
|
||||||
|
Reference in New Issue
Block a user