I'm trying to concurrently write to different parts of an image from different threads - My attempt at a multithreaded approach to rendering the mandelbrot set. I know that each thread will be writing to different pixels (no crossover) so that it is safe to do so. But I'm stuck with how to share the mutable image buffer across the threads without using a mutex (because that would defeat the purpose of having multithreading).
I am using the image crate for the ImageBuffer.
My current code is this:
/// Generates an RGB image of the specified fractal, with given
/// dimensions, and a defined transformation from the image coordinate
/// plane to the complex plane, and the max_iterations is the amount
/// of detail (50-100 being low, >=1000 being high, default 100)
pub fn generate_fractal_image(&self, fractal_type: FractalType, dimensions: (u32, u32), transform: &PlaneTransform<f64>, max_iterations: Option<u32>) -> RgbImage {
let (width, height) = dimensions;
let mut img = ImageBuffer::new(width, height);
let transform = transform.clone();
for (_, row) in img.enumerate_rows_mut() {
self.thread_pool.assign_job(move || {
for (_, (x, y, pixel)) in row.enumerate() {
let rgb = match fractal_type {
FractalType::MandelbrotSet => mandelbrot::calculate_pixel(x, y, &transform, max_iterations),
FractalType::JuliaSet => julia::calculate_pixel(x, y, &transform, max_iterations)
};
*pixel = image::Rgb([rgb.r as u8, rgb.g as u8, rgb.b as u8]);
}
});
}
img
}
And I get these errors:
error[E0597]: `img` does not live long enough
--> src/lib.rs:38:20
|
38 | for (_, row) in img.enumerate_rows_mut() {
| ^^^---------------------
| |
| borrowed value does not live long enough
| argument requires that `img` is borrowed for `'static`
...
52 | }
| - `img` dropped here while still borrowed
error[E0505]: cannot move out of `img` because it is borrowed
--> src/lib.rs:51:4
|
38 | for (_, row) in img.enumerate_rows_mut() {
| ------------------------
| |
| borrow of `img` occurs here
| argument requires that `img` is borrowed for `'static`
...
51 | img
| ^^^ move out of `img` occurs here
That makes sense, but I'm stuck as to how to share img between the threads.
I'm using a thread pool implementation based off of this chapter.
Still fairly new to rust so I'm definitely not doing things in necessarily the best way, or the "correct" way, so anything you can point out would be brilliant :)
Related
I'm learning Rust and I have this code while following a tutorial. All that this set of code does is loop through the numbers and add up the total.
enum Shot {
Bullseye,
Hit(f64),
Miss,
}
impl Shot {
fn points(self) -> i32 {
match self {
Shot::Bullseye => 5,
Shot::Hit(x) if x < 3.0 => 2,
Shot::Hit(x) => 1,
_ => 0,
}
}
}
fn main() {
let mut shots: Vec<Shot> = Vec::new();
shots.push(Shot::Bullseye);
shots.push(Shot::Hit(5.0));
shots.push(Shot::Miss);
let mut total = 0;
for shot in shots.iter() {
let points = shot.points();
total += points
}
println!("Total: {}", total);
}
However, when I run this, I get the following error:
error[E0507]: cannot move out of `*shot` which is behind a shared reference
|
68 | let points = shot.points();
| ^^^^^--------
| | |
| | `*shot` moved due to this method call
| move occurs because `*shot` has type `Shot`, which does not implement the `Copy` trait
|
note: this function takes ownership of the receiver `self`, which moves `*shot`
--> src/main.rs:21:15
|
21 | fn points(self) -> i32 {
| ^^^^
Strangely, if I change it to this, everything compiles without error:
for shot in shots {
let points = shot.points();
total += points
}
Why does it work when I remove the iterator? And yet the loop works without the iterator?
I tried deciphering the error message but still couldn't understand what is happening. In this case, I believe shot is a reference. I'm calling the shot.points() function which returns an i32 value which is owned by the variable points. Yet, the error mentioned about shot being moved due to the call on the shot.points() function?
What does the error really mean and why is that happening?
Let's try and get the actual type of shot inside the loop:
for shot in shots.iter() {
let foo: () = shot;
}
Playground
The error message tells us that shot has type &Shot. In other words, it's a shared reference to Shot. But points is defined as fn points (self) -> i32 which means that it expects an owned value, so you can't call shot.points() on a reference. As pointed out by others the fix is easy: simply change points to take a reference, i.e. fn points (&self) -> i32 (playground).
Now why does it work if we remove the .iter()? Look what happens to the type in that case:
for shot in shots {
let foo: () = shot;
}
Playground
Now shot has type Shot, no reference. This is because for shot in shots is actually equivalent to for shot in shots.into_iter(), which consumes shots and iterates over owned values. The consequence is that you can non longer use it after the loop:
for shot in shots {
}
println!("{:?}", shots);
doesn't work:
error[E0382]: borrow of moved value: `shots`
--> src/main.rs:32:22
|
20 | let mut shots: Vec<Shot> = Vec::new();
| --------- move occurs because `shots` has type `Vec<Shot>`, which does not implement the `Copy` trait
...
28 | for shot in shots {
| ----- `shots` moved due to this implicit call to `.into_iter()`
...
32 | println!("{:?}", shots);
| ^^^^^ value borrowed here after move
|
note: this function takes ownership of the receiver `self`, which moves `shots`
--> /rustc/d5a82bbd26e1ad8b7401f6a718a9c57c96905483/library/core/src/iter/traits/collect.rs:262:18
= note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider iterating over a slice of the `Vec<Shot>`'s content to avoid moving into the `for` loop
|
28 | for shot in &shots {
| +
The function points takes ownership of shot, so on the next iteration it can't do that again.
Giving what you do with shot (just reading), you may use an immutable reference to solve the issue:
fn points(&self) -> i32 {
You would also need to dereference x
Shot::Hit(x) if *x < 3.0 => 2,
Rust playground link
I'm trying to retrieve the user's lat/lon, once, in the create function of a Yew Component, so that I can do some math and pass useful decisions to child components. I've made the Yew hook "use_geolocation()" work just fine, but that only runs in a function_component, and there doesn't appear to be any straightforward way to use that location in other components.
Then I found this neat tutorial which uses wasm_bindgen and Seed::app::orders::Orders to make a "cheap clone" of the app, and to call the Javascript functions. The bindings look like:
#[wasm_bindgen]
extern "C" {
type GeolocationCoordinates;
#[wasm_bindgen(method, getter)]
fn latitude(this: &GeolocationCoordinates) -> f64;
#[wasm_bindgen(method, getter)]
fn longitude(this: &GeolocationCoordinates) -> f64;
type GeolocationPosition;
#[wasm_bindgen(method, getter)]
fn coords(this: &GeolocationPosition) ->
GeolocationCoordinates;
}
And the function for fetching geolocation, splicing together the chunks of code from Tor Hovland's tutorial:
let (app, msg_mapper) = (orders.clone_app(), orders.msg_mapper());
let geo_callback = move |position: JsValue| {
let pos: GeolocationPosition = position.into();
let coords = pos.coords();
app.update(msg_mapper(Msg::Position(
coords.latitude(),
coords.longitude(),
)));
};
let geolocation = web_sys::window()
.expect("Unable to get browser window.")
.navigator()
.geolocation()
.expect("Unable to get geolocation.");
let geo_callback_function =
Closure::wrap(
Box::new(|pos| geo_callback(pos)) as Box<dyn Fn(JsValue)>
);
geolocation.get_current_position(
&geo_callback_function.as_ref().unchecked_ref()
).expect("Unable to get position");
geo_callback_function.forget();
I attempted this route, but found that adding the line seed = "0.9.1" into my Cargo.toml produced compile errors, something about a type mismatch between a closure in wasm_bindgen and something in seed. Included here for completeness:
error[E0283]: type annotations needed for `Closure<T>`
--> /home/djmcmath/.cargo/registry/src/github.com-1ecc6299db9ec823/seed-
0.9.1/src/browser/service/routing.rs:87:9
|
87 | let closure = Closure::new(move |event: web_sys::Event| {
| ^^^^^^^
|
= note: cannot satisfy `_: WasmClosure`
note: required by a bound in `Closure::<T>::new`
--> /home/djmcmath/.cargo/registry/src/github.com-1ecc6299db9ec823/wasm-bindgen-
0.2.81/src/closure.rs:251:17
|
251 | T: ?Sized + WasmClosure,
| ^^^^^^^^^^^ required by this bound in `Closure::<T>::new`
help: consider giving `closure` an explicit type, where the type for type parameter
`T` is specified
|
87 | let closure: Closure<T> = Closure::new(move |event: web_sys::Event| {
| ++++++++++++
help: consider specifying the type argument in the function call
|
87 | let closure = Closure::new::<F>(move |event: web_sys::Event| {
| +++++
After beating my head against that brick wall for a while, I decided to just not use Seed, but I don't know of another way to make a "cheap clone" of the app to make the lifetimes work out correctly. Without that, I get the predictable lifetime error on the geo_callback_function:
let geo_callback_function =
Closure::wrap(
Box::new(|pos: JsValue| geo_callback(pos)) as Box<dyn Fn(JsValue)>
);
Error message:
error[E0597]: `geo_callback` does not live long enough
--> src/ferry_route.rs:213:37
|
213 | Box::new(|pos: JsValue| geo_callback(pos)) as Box<dyn Fn(JsValue)>
| ------------------------^^^^^^^^^^^^------
| | | |
| | | borrowed value does not live long enough
| | value captured here
| cast requires that `geo_callback` is borrowed for `'static`
...
221 | }
| - `geo_callback` dropped here while still borrowed
So I'm at a loss, at this point. Seems like fetching user's location would be simpler than all of this. I'm open to any path that makes any of these work. (Definition of work: I can get the user's lat/lon in the create function of a Yew Component, so that I can do some math and pass useful decisions to child components.)
Ok, I think I've got it. Or at least, I've got something that works. I'm not sure it's the most elegant solution. Basically, drop the Seed parts out of the function and just pull the coords from the JsValue, like so:
fn geo_callback(position: JsValue) {
let pos = JsCast::unchecked_into::<GeolocationPosition>(position);
let coords = pos.coords();
log::info!(
"Latitude: {}. Longitude: {}.",
coords.latitude(),
coords.longitude()
);
};
At this point, I'm pretty sure I can take those coords and do something useful with them.
I am working on a minesweeper copy in Rust and WASM. At the moment, I'm finishing the logic for Mine Sweeper. Mainly, when the user clicks on an empty tile with no bombs near it, the program then searches the neighbors and reveals those tiles if they are not near any bombs.
Notice the large empty spaces on the game that opens up automatically.
The program uses two 1D vectors to store where the bombs are and also what is the state of each tile.
Then this recursive program sets the state of a found empty tile to SpotState::Empty, then continues this with the neighbors.
/// for uncovering empty neighbors and recursively uncovering their empty neighbors
fn uncover_empty_neighbors(&mut self, col: usize, row: usize) {
// break case for recursion
if self.state_vec[self.get_idx(col, row)] == SpotState::Empty {
return;
}
if self.get_mine_neighbor_count(col, row) == 0 {
let idx = self.get_idx(col, row);
self.state_vec[idx] = SpotState::Empty;
}
let inbound_neighbors = POSSIBLE_NEIGHBORS
.iter()
.map(|[x, y]| [x + col as isize, y + row as isize])
.filter(|[x, y]| self.check_bounds(x, y))
.for_each(|[x, y]| self.uncover_empty_neighbors(x as usize, y as usize));
}
However, I get this error:
error[E0500]: closure requires unique access to `*self` but it is already borrowed
--> src\lib.rs:138:23
|
137 | .filter(|[x, y]| self.check_bounds(x, y))
| -------- ---- first borrow occurs due to use of `*self` in closure
| |
| borrow occurs here
138 | .for_each(|[x, y]| {
| -------- ^^^^^^^^ closure construction occurs here
| |
| first borrow later used by call
139 | self.uncover_empty_neighbors(x as usize, y as usize)
| ---- second borrow occurs due to use of `*self` in closure
For more information about this error, try `rustc --explain E0500`.
error: could not compile `minesweeper_wasm` due to previous error
warning: build failed, waiting for other jobs to finish...
error: build failed
I'm confused about how to accomplish this. Is the closure unable to capture self since self is already mutably borrowed in the function uncover_empty_neighbors()? Is using self inevitably a bad move in this case and what other data structure would be useful?
Link to repo
Yes. Remember that iterators are evaluated lazily, so the closure passed into filter needs to borrow self and keep borrowing it while for_each is executing, as for_each needs to evaluate the iterator it is called on.
You can either try to restructure the code so that either of the methods does not depend on self, or you can simply collect() into a new Vec after the filter(), so that there is no immutable borrow alive as uncover_empty_neighbors executes.
You just need to try to avoid borrowing when possible. In this case making a free method taking an owned width/height is enough, considering that they are usize which is Copy:
/// for checking the bounds of a given row and col since neighbors are blindly checked.
fn check_bounds(col: &isize, row: &isize, width: usize, height: usize) -> bool {
if col < &0 || row < &0 || col >= &(width as isize) || row >= &(height as isize) {
return false;
}
true
}
/// for uncovering empty neighbors
fn uncover_empty_neighbors(&mut self, col: usize, row: usize) {
// break case for recursion
if self.state_vec[self.get_idx(col, row)] == SpotState::Empty {
return;
}
if self.get_mine_neighbor_count(col, row) == 0 {
let idx = self.get_idx(col, row);
self.state_vec[idx] = SpotState::Empty;
}
let (width, height) = (self.width, self.height);
let inbound_neighbors = POSSIBLE_NEIGHBORS
.iter()
.map(|[x, y]| [x + col as isize, y + row as isize])
.filter(|[x, y]| Self::check_bounds(x, y, width, height))
.for_each(|[x, y]| {
self.uncover_empty_neighbors(x.clone() as usize, y.clone() as usize)
});
}
Playground
What is going on? Well, you are capturing self withing the closures that the iterator use, since iterators are lazy that borrow is not release until you collect (or in your case the whole for_each is evaluated).
This question already has answers here:
Cannot infer an appropriate lifetime for autoref due to conflicting requirements
(1 answer)
Why can't I store a value and a reference to that value in the same struct?
(4 answers)
Closed 3 years ago.
I'm using the rust-sdl2 crate to paint a buffer on a window screen, so I decided to abstract the SDL calls. I tried to follow this example from the rust-sdl2 repo and my first thought was to create something like this:
pub struct SDLDisplay {
sdl_context: Sdl,
video_subsystem: VideoSubsystem,
canvas: WindowCanvas,
texture_creator: TextureCreator<sdl2::video::WindowContext>,
texture: Texture,
}
impl SDLDisplay {
pub fn new() -> Result<SDLDisplay, String> {
let sdl_context = sdl2::init()?;
let video_subsystem = sdl_context.video()?;
let window = video_subsystem
.window("Test App", 256, 240)
.position_centered()
.build()
.map_err(|e| e.to_string())?;
let canvas = window.into_canvas().build().map_err(|e| e.to_string())?;
let texture_creator = canvas.texture_creator();
let texture = texture_creator
.create_texture_streaming(Some(ARGB8888), 256, 240)
.map_err(|e| e.to_string())?;
Ok(SDLDisplay {
sdl_context,
video_subsystem,
canvas,
texture_creator,
texture,
})
}
}
The first issue was that Texture needs a lifetime parameter; I solved that by spreading an <'a> across the code base... It stopped complaining about that, but now I have the following:
error[E0515]: cannot return value referencing local variable `texture_creator`
|
--> src/sdl_display.rs:44:9
40 | let texture = texture_creator
| --------------- `texture_creator` is borrowed here
|
...
40 | let texture = texture_creator
44 | / Ok(SDLDisplay {
| --------------- `texture_creator` is borrowed here
45 | | sdl_context,
...
46 | | video_subsystem,
44 | / Ok(SDLDisplay {
47 | | canvas,
45 | | sdl_context,
48 | | texture_creator,
46 | | video_subsystem,
49 | | texture,
47 | | canvas,
48 | | texture_creator,
49 | | texture,
50 | | })
| |__________^ returns a value referencing data owned by the current function
50 | | })
| |__________^ returns a value referencing data owned by the current function
It's telling me I can't move texture_creator to the new struct because it was borrowed for creating the texture, but if I don't have the TextureCreator instance inside the struct, it complains that Texture must not outlive TextureCreator.
I'm completely lost here. Is there a way to actually store a texture inside a struct using rust-sdl2?
This question already has an answer here:
How can I pass a reference to a stack variable to a thread?
(1 answer)
Closed 3 years ago.
I am trying to write a binary tree that can be passed around between threads without having to be copied every time. I'm having a hard time understanding how to do this with Rust's restrictions around lifetimes.
use std::thread::spawn;
#[derive(Debug)]
struct Node<'a> {
left: &'a i32,
right: &'a i32,
}
fn main() {
let l = 3;
let r = 4;
let n = Node {
left: &l,
right: &r,
};
spawn(|| {
println!("{:?}", n);
});
}
error[E0597]: `l` does not live long enough
--> src/main.rs:13:15
|
13 | left: &l,
| ^^ borrowed value does not live long enough
...
17 | / spawn(|| {
18 | | println!("{:?}", n);
19 | | });
| |______- argument requires that `l` is borrowed for `'static`
20 | }
| - `l` dropped here while still borrowed
error[E0597]: `r` does not live long enough
--> src/main.rs:14:16
|
14 | right: &r,
| ^^ borrowed value does not live long enough
...
17 | / spawn(|| {
18 | | println!("{:?}", n);
19 | | });
| |______- argument requires that `r` is borrowed for `'static`
20 | }
| - `r` dropped here while still borrowed
error[E0373]: closure may outlive the current function, but it borrows `n`, which is owned by the current function
--> src/main.rs:17:11
|
17 | spawn(|| {
| ^^ may outlive borrowed value `n`
18 | println!("{:?}", n);
| - `n` is borrowed here
|
note: function requires argument type to outlive `'static`
--> src/main.rs:17:5
|
17 | / spawn(|| {
18 | | println!("{:?}", n);
19 | | });
| |______^
help: to force the closure to take ownership of `n` (and any other referenced variables), use the `move` keyword
|
17 | spawn(move || {
| ^^^^^^^
I understand why it would think they don't live long enough, but how should I restructure this so that they do?
In your situation, you create a Node object with references to variables you defined in your main() function, and pass it to a new thread. The problem is that you have absolutely no guarantee that this thread will finish before the thread of your main(), and you risk your original variables going out of scope before the references, hence the error.
Given that you wish to build a tree, I think the easiest fix would be to have your Node type own its fields, like this:
#[derive(Debug)]
struct Node {
left: i32,
right: i32,
}
you will then have no more lifetime issues.
To share it between several threads without copying it, you can use the std::sync::Arc wrapper; it's for exactly this purpose. You can do something like:
use std::sync::Arc;
fn main() {
let n = Arc::new(Node { left: 3, right: 4 });
for _ in 0..10 {
let n_thread = n.clone();
spawn(move || {
println!("{:?}", n_thread);
});
}
}
If you need to give your other threads write access to the Node as well, you probably will want to wrap it in a Mutex or a RwLock, keeping whole thing inside an Arc.