Catch exceptions from tasks #7072
No reviewers
Labels
No Label
Closed
Duplicate
Closed
Fixed
Closed
Invalid
Closed
Needs info
Closed
Won't fix
Closed
Works for me
Difficulty
Hard
Difficulty
Medium
Difficulty
Simple
Needed for Beta
Needs Design Input
Needs Info
Pathfinding
Priority
1: Release Blocker
Priority
2: Must Have
Priority
3: Should Have
Priority
4: Nice To Have
Priority
5: If Time Permits
Regression
Theme
AI
Theme
Art & Animation
Theme
Atlas editor
Theme
Build & Packages
Theme
Core engine
Theme
Documentation
Theme
Internationalization & Localization
Theme
Maps
Theme
Multiplayer Lobby
Theme
Music & Sound FX
Theme
Network
Theme
Non-game systems
Theme
Simulation
Theme
UI & Simulation
Theme
UI β Game setup
Theme
UI β In-game
Theme
UI β Miscellaneous
Theme
Website & Forum
Type
Defect
Type
Enhancement
Type
Task
No Milestone
No project
No Assignees
2 Participants
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: 0ad/0ad#7072
Loadingβ¦
Reference in New Issue
Block a user
No description provided.
Delete Branch "phosit/0ad:task_exception"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
It's now possible te get an exception from a function in a task.
The interface is like std::future: if you call .Get() you will get the result (as before) or the exception will be thrown.
I don't know if this also does handle windows structured exceptions. See: https://learn.microsoft.com/en-us/cpp/cpp/transporting-exceptions-between-threads
Ref: #5874
Continuation of https://code.wildfiregames.com/D4956
@ -107,2 +105,3 @@
// The caller must ensure that this is only called if we have a result.
ENSURE(this->has_value());
if constexpr (!std::is_void_v<ResultType>)
ENSURE(std::get<0>(m_Outcome).has_value() || std::get<1>(m_Outcome));
Isn't explicit typing more clear and safe?
Normally i use
std::tuple
only with indexes. But in this case it's cleaner with types.The benefit will be more apperent when we switch to
std::variant
.Why do we need to switch to
std::variant
here?A task can't result with a value and an exception.
An
std::variant
would clarify that.@ -133,0 +139,4 @@
using std::exception::exception;
};
{
You might split for different test_exception_* cases for a more clear report.
@ -802,2 +800,3 @@
// We're done, get the exceptions from the futures.
for (Future<void>& future : m_Futures)
future.CancelOrWait();
future.Get();
Code seems a bit strange, why do we call Get if we don't use the result? The CancelOrWait version seems more clear.
Like the comment explains it's done to get the exceptions from the tasks.
The interface is like
std::future
.Yeah, I read the comment but the naming is confusing for me. I'd prefer to have something more explicit like:
Meh... I'd go with the semantics of
std::future
.A
Future<T>::Get
call does wait for the task to finish, if the task ended in an exception rethrow that and in the other case return what the task returned.A
Future<void>::Get
call does everything of the above.The caller code is more consistent: A simple guideline could be "call
Future<T>::Get
on each Future". Where in your proposal it "callFuture<T>::Get
on each Future except if it's aFuture<void>
then you have to callFuture<void>::WaitAndThrowIfNeeded
."The library is more consistent: There is less SFINAE.
Peoply might be confused that they think they have to call
Future<T>::WaitAndThrowIfNeeded
andFuture<void>::Get
.95e2c6e4a6
to95a58ab083
95a58ab083
tobb87204917