mirror of
https://github.com/vcmi/vcmi.git
synced 2026-06-19 22:57:37 +02:00
Merge pull request #6934 from IvanSavenko/ai_freeze_fix
Try to fix possible freezes on AI actions
This commit is contained in:
+16
-22
@@ -608,7 +608,7 @@ void AIGateway::yourTurn(QueryID queryID)
|
||||
|
||||
nullkiller->makingTurnInterrupption.reset();
|
||||
|
||||
asyncTasks->run([this]()
|
||||
asyncTasks->run([this]() noexcept
|
||||
{
|
||||
ScopedThreadName guard("NKAI::AIGateway::makingTurn");
|
||||
makeTurn();
|
||||
@@ -850,7 +850,7 @@ bool AIGateway::makePossibleUpgrades(const CArmedInstance * obj)
|
||||
return upgraded;
|
||||
}
|
||||
|
||||
void AIGateway::makeTurn()
|
||||
void AIGateway::makeTurn() noexcept
|
||||
{
|
||||
MAKING_TURN;
|
||||
|
||||
@@ -877,10 +877,8 @@ void AIGateway::makeTurn()
|
||||
}
|
||||
}
|
||||
|
||||
#if NKAI_TRACE_LEVEL == 0
|
||||
try
|
||||
{
|
||||
#endif
|
||||
nullkiller->makeTurn();
|
||||
|
||||
//for debug purpose
|
||||
@@ -889,28 +887,17 @@ void AIGateway::makeTurn()
|
||||
if (h->movementPointsRemaining())
|
||||
logAi->info("Hero %s has %d MP left", h->getNameTranslated(), h->movementPointsRemaining());
|
||||
}
|
||||
#if NKAI_TRACE_LEVEL == 0
|
||||
}
|
||||
catch (const TerminationRequestedException &)
|
||||
{
|
||||
logAi->debug("Making turn thread has been interrupted. We'll end without calling endTurn.");
|
||||
return;
|
||||
}
|
||||
catch (const std::exception & e)
|
||||
{
|
||||
logAi->debug("Making turn thread has caught an exception: %s", e.what());
|
||||
}
|
||||
#endif
|
||||
|
||||
try
|
||||
{
|
||||
endTurn();
|
||||
}
|
||||
catch (const TerminationRequestedException &)
|
||||
catch (const InterruptionRequestedException &)
|
||||
{
|
||||
logAi->debug("Making turn thread has been interrupted. We'll end without calling endTurn.");
|
||||
return;
|
||||
}
|
||||
catch (const TerminationRequestedException &)
|
||||
{
|
||||
logAi->debug("Making turn thread has been terminated. We'll end without calling endTurn");
|
||||
}
|
||||
}
|
||||
|
||||
void AIGateway::performObjectInteraction(const CGObjectInstance * obj, HeroPtr h)
|
||||
@@ -1632,12 +1619,19 @@ void AIGateway::executeActionAsync(const std::string & description, const std::f
|
||||
if (!asyncTasks)
|
||||
throw std::runtime_error("Attempt to execute task on shut down AI state!");
|
||||
|
||||
asyncTasks->run([this, description, whatToDo]()
|
||||
asyncTasks->run([this, description, whatToDo]() noexcept
|
||||
{
|
||||
ScopedThreadName guard("NKAI::AIGateway::" + description);
|
||||
SET_GLOBAL_STATE(this);
|
||||
std::shared_lock gsLock(CGameState::mutex);
|
||||
whatToDo();
|
||||
try
|
||||
{
|
||||
whatToDo();
|
||||
}
|
||||
catch (const TerminationRequestedException &)
|
||||
{
|
||||
logAi->debug("%s thread has been terminated. We'll end it immediately", description);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -155,7 +155,7 @@ public:
|
||||
|
||||
void invalidatePaths() override;
|
||||
|
||||
void makeTurn();
|
||||
void makeTurn() noexcept;
|
||||
|
||||
void buildArmyIn(const CGTownInstance * t);
|
||||
void endTurn();
|
||||
|
||||
@@ -531,7 +531,7 @@ void AIGateway::yourTurn(QueryID queryID)
|
||||
|
||||
nullkiller->makingTurnInterruption.reset();
|
||||
|
||||
asyncTasks->run([this]()
|
||||
asyncTasks->run([this]() noexcept
|
||||
{
|
||||
ScopedThreadName guard("NK2AI::AIGateway::makingTurn");
|
||||
status.waitTillFree();
|
||||
@@ -764,18 +764,18 @@ bool AIGateway::makePossibleUpgrades(const CArmedInstance * obj)
|
||||
return upgraded;
|
||||
}
|
||||
|
||||
void AIGateway::makeTurn()
|
||||
void AIGateway::makeTurn() noexcept
|
||||
{
|
||||
auto day = cc->getDate(Date::DAY);
|
||||
logAi->info("Player %d (%s) starting turn, day %d", playerID, playerID.toString(), day);
|
||||
|
||||
std::shared_lock gsLock(CGameState::mutex);
|
||||
cheatMapReveal(nullkiller);
|
||||
memorizeVisitableObjs(nullkiller->memory, nullkiller->dangerHitMap, playerID, cc);
|
||||
memorizeRevisitableObjs(nullkiller->memory, playerID, cc);
|
||||
|
||||
try
|
||||
{
|
||||
auto day = cc->getDate(Date::DAY);
|
||||
logAi->info("Player %d (%s) starting turn, day %d", playerID, playerID.toString(), day);
|
||||
|
||||
std::shared_lock gsLock(CGameState::mutex);
|
||||
cheatMapReveal(nullkiller);
|
||||
memorizeVisitableObjs(nullkiller->memory, nullkiller->dangerHitMap, playerID, cc);
|
||||
memorizeRevisitableObjs(nullkiller->memory, playerID, cc);
|
||||
|
||||
const auto start = std::chrono::high_resolution_clock::now();
|
||||
nullkiller->makeTurn();
|
||||
const auto timeElapsedMs = timeElapsed(start);
|
||||
@@ -789,24 +789,17 @@ void AIGateway::makeTurn()
|
||||
if (h->movementPointsRemaining())
|
||||
logAi->warn("Hero %s has %d MP left", h->getNameTranslated(), h->movementPointsRemaining());
|
||||
}
|
||||
}
|
||||
catch (const TerminationRequestedException &)
|
||||
{
|
||||
logAi->debug("Making turn thread has been interrupted while nullkiller->makeTurn(). We'll end without calling endTurn.");
|
||||
return;
|
||||
}
|
||||
catch (const std::exception & e)
|
||||
{
|
||||
logAi->error("Making turn thread has caught an exception: %s", e.what());
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
endTurn();
|
||||
}
|
||||
catch (const InterruptionRequestedException &)
|
||||
{
|
||||
logAi->debug("Making turn thread has been interrupted. We'll end without calling endTurn.");
|
||||
return;
|
||||
}
|
||||
catch (const TerminationRequestedException &)
|
||||
{
|
||||
logAi->debug("Making turn thread has been interrupted endTurn().");
|
||||
logAi->debug("Making turn thread has been terminated. We'll end without calling endTurn");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1361,14 +1354,8 @@ void AIGateway::finish()
|
||||
|
||||
if (asyncTasks)
|
||||
{
|
||||
try {
|
||||
asyncTasks->wait();
|
||||
asyncTasks.reset();
|
||||
}
|
||||
catch (const TerminationRequestedException &)
|
||||
{
|
||||
// ignore, tbb caught this exception from task and propagated it to our thread
|
||||
}
|
||||
asyncTasks->wait();
|
||||
asyncTasks.reset();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1377,11 +1364,18 @@ void AIGateway::executeActionAsync(const std::string & description, const std::f
|
||||
if (!asyncTasks)
|
||||
throw std::runtime_error("Attempt to execute task on shut down AI state!");
|
||||
|
||||
asyncTasks->run([description, whatToDo]()
|
||||
asyncTasks->run([description, whatToDo]() noexcept
|
||||
{
|
||||
ScopedThreadName guard("NK2AI::AIGateway::" + description);
|
||||
std::shared_lock gsLock(CGameState::mutex);
|
||||
whatToDo();
|
||||
try
|
||||
{
|
||||
whatToDo();
|
||||
}
|
||||
catch (const TerminationRequestedException &)
|
||||
{
|
||||
logAi->debug("%s thread has been terminated. We'll end it immediately", description);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -155,7 +155,7 @@ public:
|
||||
|
||||
void invalidatePaths() override;
|
||||
|
||||
void makeTurn();
|
||||
void makeTurn() noexcept;
|
||||
|
||||
void buildArmyIn(const CGTownInstance * t);
|
||||
void endTurn();
|
||||
|
||||
@@ -490,6 +490,7 @@ void Nullkiller::makeTurn()
|
||||
{
|
||||
logAi->info(
|
||||
"Pass %d: Heroes can still move but goal %s has too low priority %f. Increasing to ScanDepth::ALL_FULL",
|
||||
pass,
|
||||
taskDescription,
|
||||
selectedTask->priority);
|
||||
|
||||
|
||||
+12
-1
@@ -24,6 +24,17 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class InterruptionRequestedException : public std::exception
|
||||
{
|
||||
public:
|
||||
using exception::exception;
|
||||
|
||||
const char* what() const noexcept override
|
||||
{
|
||||
return "Thread termination requested";
|
||||
}
|
||||
};
|
||||
|
||||
class ThreadInterruption
|
||||
{
|
||||
std::atomic<bool> interruptionRequested = false;
|
||||
@@ -34,7 +45,7 @@ public:
|
||||
bool result = interruptionRequested.exchange(false);
|
||||
|
||||
if (result)
|
||||
throw TerminationRequestedException();
|
||||
throw InterruptionRequestedException();
|
||||
}
|
||||
|
||||
void interruptThread()
|
||||
|
||||
Reference in New Issue
Block a user