-
Notifications
You must be signed in to change notification settings - Fork 6
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
Grid provider for Plain #77
Conversation
The GridCollection struct provides access to Arc<dyn Grid>, such that any grid needed by any Operator in any instantiation of Plain, always refer to the same meap allocation.
No strong opinions. It looks sensible to me. For my own benefit, could you explain why the |
Not really sure why, but it does not compile without. This code: unsafe { GRIDS.lock().unwrap().get_grid(name, self.paths.clone()) } modifies (i.e. may modify) this static struct: static mut GRIDS: Mutex<GridCollection> =
Mutex::new(GridCollection(BTreeMap::<String, Arc<dyn Grid>>::new())); which I believe should be (thread)-safe, due to the error[E0133]: use of mutable static is unsafe and requires unsafe function or block
--> src\context\plain.rs:256:9
|
256 | GRIDS.lock().unwrap().get_grid(name, self.paths.clone())
| ^^^^^^^^^^^^ use of mutable static
|
= note: mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior ...which is formally correct, but which I assumed I had mitigated by putting the access behind a |
Plain now uses a global BTreeMap for holding Arc<dyn Grid>, and hands out Arc::clone()s to Ops needing access. This means that all uses of a grid refers to the same heap allocation. Unfortunately, we need to keep the "original" instantiation in the list, so the Arcs will never be fully released. To mitigate this, we empty the BTreeMap every time a new Plain is instantiated. While not ideal, it limits the risk of hanging on to needless heap allocations
Ah interesting, thanks for those details @busstoptaktik. I posed the question to Github Copilot which said:
A bit more reading suggests that it's because it breaks the borrow checking rules of having exactly on mutable borrow at any point. I take it to mean that by having a global Deeper down the rabbit hole I came across the once_cell crate which provides a |
Huge thanks, for the analysis and solution, @Rennzie! I have merged & pushed this on main |
The GridCollection struct provides access to
Arc<dyn Grid>
, such that any grid needed by any Operator in any instantiation of Plain, always refer to the same heap allocation.Unfortunately, this requires one line of
unsafe{...}
code.We could have achieved almost-the-same, by building the collection into Plain herself. But this would also require that the InnerOp::new() methods switch to take a
&mut Context
, which may have cascading effects all through the code. Hence I prefer this solution.@Rennzie do you have any opinions about this?