-
Notifications
You must be signed in to change notification settings - Fork 407
Improvements to thread safety #2736
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improvements to thread safety #2736
Conversation
068184b to
9f6e2fe
Compare
2844810 to
71e3c67
Compare
- Fix a race condition in the Document cache, where the `valid` flag could be simultaneously written and read from different threads. - Add an initial Thread Safety section to the Developer Guidelines.
71e3c67 to
88cfd14
Compare
source/MaterialXCore/Document.cpp
Outdated
| void setDocument(weak_ptr<Document> document) | ||
| { | ||
| _doc = document; | ||
| invalidate(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What happens if another thread tries to fetch cached data in the miniscule moment after _doc is set, but before invalidate() has had the time to set _valid to false?
I would recommend using a C++17 std::shared_mutex instead for robustness. It allows multiple-reader/single-writer semantics.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's a really good suggestion, @JGamache-autodesk, and I've updated the PR to use this approach.
Following up on review notes from Jerry Gamache, this change switches over to a std::shared_mutex pattern, which should be simpler and more robust.
| const string& nodeGraphName = elem->getAttribute(PortElement::NODE_GRAPH_ATTRIBUTE); | ||
| const string& nodeString = elem->getAttribute(NodeDef::NODE_ATTRIBUTE); | ||
| const string& nodeDefString = elem->getAttribute(InterfaceElement::NODE_DEF_ATTRIBUTE); | ||
| lock.unlock(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks! That is the best currently possible with C++ (up to 23). Rechecking the _valid condition after re-acquiring the lock makes sure we handle the case where another thread pre-emptively rebuilds in the small window after the shared lock is released, especially since this thread now has to wait for all shared locks to be released before proceeding.
LGTM!
5961041
into
AcademySoftwareFoundation:main
validflag could be simultaneously written and read from different threads.std::shared_mutexpattern in the Document cache for greater robustness and clearer guarantees.