Threaded calling of functions in a vector - multithreading

I have an EventRegistry which people can use to register event listeners. It then calls the appropriate listeners when an event is broadcast. But, when I try to multithread it, it doesn't compile. How would I get this code working?
use std::collections::HashMap;
use std::thread;
struct EventRegistry<'a> {
event_listeners: HashMap<&'a str, Vec<Box<Fn() + Sync>>>
}
impl<'a> EventRegistry<'a> {
fn new() -> EventRegistry<'a> {
EventRegistry {
event_listeners: HashMap::new()
}
}
fn add_event_listener(&mut self, event: &'a str, listener: Box<Fn() + Sync>) {
match self.event_listeners.get_mut(event) {
Some(listeners) => {
listeners.push(listener);
return
},
None => {}
};
let mut listeners = Vec::with_capacity(1);
listeners.push(listener);
self.event_listeners.insert(event, listeners);
}
fn broadcast_event(&mut self, event: &str) {
match self.event_listeners.get(event) {
Some(listeners) => {
for listener in listeners.iter() {
let _ = thread::spawn(|| {
listener();
});
}
}
None => {}
}
}
}
fn main() {
let mut main_registry = EventRegistry::new();
main_registry.add_event_listener("player_move", Box::new(|| {
println!("Hey, look, the player moved!");
}));
main_registry.broadcast_event("player_move");
}
Playpen (not sure if it's minimal, but it produces the error)
If I use thread::scoped, it works too, but that's unstable, and I think it only works because it immediately joins back to the main thread.

Updated question
I meant "call them in their own thread"
The easiest thing to do is avoid the Fn* traits, if possible. If you know that you are only using full functions, then it's straightforward:
use std::thread;
fn a() { println!("a"); }
fn b() { println!("b"); }
fn main() {
let fns = vec![a as fn(), b as fn()];
for &f in &fns {
thread::spawn(move || f());
}
thread::sleep_ms(500);
}
If you can't use that for some reason (like you want to accept closures), then you will need to be a bit more explicit and use Arc:
use std::thread;
use std::sync::Arc;
fn a() { println!("a"); }
fn b() { println!("b"); }
fn main() {
let fns = vec![
Arc::new(Box::new(a) as Box<Fn() + Send + Sync>),
Arc::new(Box::new(b) as Box<Fn() + Send + Sync>),
];
for f in &fns {
let my_f = f.clone();
thread::spawn(move || my_f());
}
thread::sleep_ms(500);
}
Here, we can create a reference-counted trait object. We can clone the trait object (increasing the reference count) each time we spawn a new thread. Each thread gets its own reference to the trait object.
If I use thread::scoped, it works too
thread::scoped is pretty awesome; it's really unfortunate that it needed to be marked unstable due to some complex interactions that weren't the best.
One of the benefits of a scoped thread is that the thread is guaranteed to end by a specific time: when the JoinGuard is dropped. That means that scoped threads are allowed to contain non-'static references, so long as those references last longer than the thread!
A spawned thread has no such guarantees about how long they live; these threads may live "forever". Any references they take must also live "forever", thus the 'static restriction.
This serves to explain your original problem. You have a vector with a non-'static lifetime, but you are handing references that point into that vector to the thread. If the vector were to be deallocated before the thread exited, you could attempt to access undefined memory, which leads to crashes in C or C++ programs. This is Rust helping you out!
Original question
Call functions in vector without consuming them
The answer is that you just call them:
fn a() { println!("a"); }
fn b() { println!("b"); }
fn main() {
let fns = vec![Box::new(a) as Box<Fn()>, Box::new(b) as Box<Fn()>];
fns[0]();
fns[1]();
fns[0]();
fns[1]();
}
Playpen

Related

Unexpected Issue when Using defer-lite in combination with a Mutable Struct

I'm quite new to Rust but I've run into a strange issue that is likely me misunderstanding how the defer-lite crate works.
If I have the below code then everything is working as expected
use defer_lite::defer;
fn main() {
println!("Start");
defer! {
println!("Stop");
}
println!("Interval");
}
I get the output that I want as
Start
Interval
Stop
Then when I try to include a mutable struct
use defer_lite::defer;
struct Timer {
start:i32, interval:i32, stop:i32
}
fn timer_initialize() -> Timer {
let timer = Timer{start:0, interval:0, stop:0 };
return timer;
}
impl Timer {
fn timer_start(&mut self) { self.start = 1; }
fn timer_interval(&mut self) { self.interval = 2; }
fn timer_stop(&mut self) { self.stop = 3; }
}
fn main() {
let mut timer = timer_initialize();
println!("Start");
timer.timer_start();
defer! {
println!("Stop");
timer.timer_stop();
}
println!("Interval");
// uncommenting this line will cause a compiler error
//timer.timer_interval();
}
Everything still works fine until I try to use the struct methods below the defer! at which point I will get a compiler error
timer.timer_interval();
^^^^^^^^^^^^^^^^^^^^^^ second mutable borrow occurs here
I'm not sure why this is and if I am using defer-lite wrong
This is a limitation of this crate. This cannot be implemented in Rust. The problem is that in order to do its work, defer-lite creates a RAII guard that holds the cleanup code as a closure. But the closure holds a mutable reference to the value, so you cannot use it again until it is dropped - at the end of the scope.
If you need that I'd recommend the scopeguard crate which is also much more popular. It provides a guard() function for this case. It works like:
fn main() {
let mut timer = timer_initialize();
println!("Start");
timer.timer_start();
let mut timer = scopeguard::guard(timer, |mut timer| {
println!("Stop");
timer.timer_stop();
});
println!("Interval");
timer.timer_interval();
}

How to avoid incurring in lifetime errors while filter with an `async` predicate?

Using an async predicate to filter a list of values makes Rust complain about lifetimes. Even if the collection is awaited, which means the predicate will not outlive the filtered value, Rust remains skeptical.
Full repro below with playground here. Note that it filters on a non-copy struct we'd rather pass by reference, rather than a simple value we could just copy and forget without incurring in overhead.
use futures::stream::iter;
use futures::StreamExt;
#[derive(Debug)]
struct Foo {
bar: usize
}
impl Foo {
fn new(bar: usize) -> Self {
Self {
bar
}
}
}
#[tokio::main]
async fn main() {
let arr = vec![
Foo::new(0),
Foo::new(1),
Foo::new(2)
];
let filtered = iter(arr)
.filter(|f| async {compute_baz(f).await > 0})
.collect::<Vec<_>>()
.await;
// should print Foo{bar:1} and Foo{bar:2}
println!("{:?}", filtered)
}
async fn compute_baz(foo: &Foo) -> usize {
// ...do lengthy task...
foo.bar
}
Update
As #Ceasar pointed out below, the async functions are not run in parallel, can that be done?
I'm trying to do something like:
let filter_mask = join_all(items.map(predicate));
let filtered = items.filter(|i| filter_mask[i]).collect::<Vec<_>>();
without the clutter.
An easy workaround is to avoid the closure:
let mut filtered = vec![];
for f in arr.iter() {
if compute_baz(f).await > 0 {
filtered.push(f);
}
}

How to idiomatically share data between closures with wasm-bindgen?

In my browser application, two closures access data stored in a Rc<RefCell<T>>. One closure mutably borrows the data, while the other immutably borrows it. The two closures are invoked independently of one another, and this will occasionally result in a BorrowError or BorrowMutError.
Here is my attempt at an MWE, though it uses a future to artificially inflate the likelihood of the error occurring:
use std::cell::RefCell;
use std::future::Future;
use std::pin::Pin;
use std::rc::Rc;
use std::task::{Context, Poll, Waker};
use wasm_bindgen::prelude::*;
use wasm_bindgen::JsValue;
#[wasm_bindgen]
extern "C" {
#[wasm_bindgen(js_namespace = console)]
pub fn log(s: &str);
#[wasm_bindgen(js_name = setTimeout)]
fn set_timeout(closure: &Closure<dyn FnMut()>, millis: u32) -> i32;
#[wasm_bindgen(js_name = setInterval)]
fn set_interval(closure: &Closure<dyn FnMut()>, millis: u32) -> i32;
}
pub struct Counter(u32);
#[wasm_bindgen(start)]
pub async fn main() -> Result<(), JsValue> {
console_error_panic_hook::set_once();
let counter = Rc::new(RefCell::new(Counter(0)));
let counter_clone = counter.clone();
let log_closure = Closure::wrap(Box::new(move || {
let c = counter_clone.borrow();
log(&c.0.to_string());
}) as Box<dyn FnMut()>);
set_interval(&log_closure, 1000);
log_closure.forget();
let counter_clone = counter.clone();
let increment_closure = Closure::wrap(Box::new(move || {
let counter_clone = counter_clone.clone();
wasm_bindgen_futures::spawn_local(async move {
let mut c = counter_clone.borrow_mut();
// In reality this future would be replaced by some other
// time-consuming operation manipulating the borrowed data
SleepFuture::new(5000).await;
c.0 += 1;
});
}) as Box<dyn FnMut()>);
set_timeout(&increment_closure, 3000);
increment_closure.forget();
Ok(())
}
struct SleepSharedState {
waker: Option<Waker>,
completed: bool,
closure: Option<Closure<dyn FnMut()>>,
}
struct SleepFuture {
shared_state: Rc<RefCell<SleepSharedState>>,
}
impl Future for SleepFuture {
type Output = ();
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let mut shared_state = self.shared_state.borrow_mut();
if shared_state.completed {
Poll::Ready(())
} else {
shared_state.waker = Some(cx.waker().clone());
Poll::Pending
}
}
}
impl SleepFuture {
fn new(duration: u32) -> Self {
let shared_state = Rc::new(RefCell::new(SleepSharedState {
waker: None,
completed: false,
closure: None,
}));
let state_clone = shared_state.clone();
let closure = Closure::wrap(Box::new(move || {
let mut state = state_clone.borrow_mut();
state.completed = true;
if let Some(waker) = state.waker.take() {
waker.wake();
}
}) as Box<dyn FnMut()>);
set_timeout(&closure, duration);
shared_state.borrow_mut().closure = Some(closure);
SleepFuture { shared_state }
}
}
panicked at 'already mutably borrowed: BorrowError'
The error makes sense, but how should I go about resolving it?
My current solution is to have the closures use try_borrow or try_borrow_mut, and if unsuccessful, use setTimeout for an arbitrary amount of time before attempting to borrow again.
Think about this problem independently of Rust's borrow semantics. You have a long-running operation that's updating some shared state.
How would you do it if you were using threads? You would put the shared state behind a lock. RefCell is like a lock except that you can't block on unlocking it — but you can emulate blocking by using some kind of message-passing to wake up the reader.
How would you do it if you were using pure JavaScript? You don't automatically have anything like RefCell, so either:
The state can be safely read while the operation is still ongoing (in a concurrency-not-parallelism sense): in this case, emulate that by not holding a single RefMut (result of borrow_mut()) alive across an await boundary.
The state is not safe to be read: you'd either write something lock-like as described above, or perhaps arrange so that it's only written once when the operation is done, and until then, the long-running operation has its own private state not shared with the rest of the application (so there can be no BorrowError conflicts).
Think about what your application actually needs and pick a suitable solution. Implementing any of these solutions will most likely involve having additional interior-mutable objects used for communication.

still trying to reimplement a c++ timerqueue in rust

more on reimplementing c++ timerqueue in rust
This code tries to create a vec of tasks and run them on a different thread. Still cannot compile it. I am at the point of typing words at random into random locations to see if it helps , 'static here, move there dyn sync ,....
I think if I were to see a working version I would be able to work out why I was stuck. But I cannot make it go.
heres the complete code
use std::thread;
use std::time::Instant;
fn main() {
let x = || {
println!("hello");
};
let y = || {
println!("hello2");
};
let mut tq = TimerQueue::new();
tq.set(Box::new(x), String::from("yo"), Instant::now());
tq.set(Box::new(y), String::from("yo"), Instant::now());
tq.thr();
}
pub struct TimerQueueItem {
when: Instant,
name: String,
what: QIFunc,
}
type QIFunc = Box<dyn Fn() -> () + Send>;
struct TimerQueue {
queue: Vec<TimerQueueItem>,
}
impl TimerQueue {
fn thr(&mut self) -> () {
thread::spawn(move || {
self.runq();
});
}
fn set(&mut self, f: QIFunc, n: String, when: Instant) {
let qi = TimerQueueItem {
what: f,
name: n,
when: when,
};
self.queue.push(qi);
}
fn new() -> TimerQueue {
TimerQueue { queue: Vec::new() }
}
fn runq(&mut self) -> () {
for qi in self.queue.iter() {
(qi.what)();
}
}
}
all sorts of errors all pointing at the same place
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
--> src\main.rs:31:23
|
31 | thread::spawn(move || {
| _______________________^
32 | | self.runq();
33 | | });
| |_________^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 30:5...
--> src\main.rs:30:5
this one seems particularly designed to confuse
= note: expected `&mut TimerQueue`
found `&mut TimerQueue`
Your TimerQueue object is stored on the stack of the main thread. Because Rust cannot guarantee that the new thread will finish before the main one, it has imposed some restrictions on how you can pull off recreating your timerqueue.
I actually found a simple fix. Basically, I removed the thr method and moved its body into main.
use std::thread;
use std::time::Instant;
fn main() {
let x = || {
println!("hello");
};
let y = || {
println!("hello2");
};
let mut tq = TimerQueue::new();
tq.set(Box::new(x), String::from("yo"), Instant::now());
tq.set(Box::new(y), String::from("yo"), Instant::now());
thread::spawn(move || {
tq.runq();
});
thread::sleep_ms(1000);
}
pub struct TimerQueueItem {
when: Instant,
name: String,
what: QIFunc,
}
type QIFunc = Box<dyn Fn() -> () + Send>;
struct TimerQueue {
queue: Vec<TimerQueueItem>,
}
impl TimerQueue {
fn set(&mut self, f: QIFunc, n: String, when: Instant) {
let qi = TimerQueueItem {
what: f,
name: n,
when: when,
};
self.queue.push(qi);
}
fn new() -> TimerQueue {
TimerQueue { queue: Vec::new() }
}
fn runq(&mut self) -> () {
for qi in self.queue.iter() {
(qi.what)();
}
}
}
Note: I added the
thread::sleep_ms(1000);
which ensures that the main thread will last as long as the spawned thread - at least in this example, other scenarios might have the new thread require more time. If you want to pause the main thread until the spawned one completes (regardless of how long the spawned one takes), you can replace
thread::spawn(move || {
tq.runq();
});
thread::sleep_ms(1000);
with
let thread_handle = thread::spawn(move || {
tq.runq();
});
thread_handle.join();
For reference, my cargo version is 1.41.0
Instead of thr(&mut self), write thr(mut self).
(mut because runq wants a mutable reference. It might not need to though.)
You can't transfer ownership of the TimerQueue to the new thread with just a reference. When you "move" something into a closure, you transfer ownership there. On the other hand, if you didn't move (i.e. left the move keyword out), you couldn't ensure that self would live long enough.
A C++ analogy to this would be
// BAD: v may go out of scope in the main
// thread before the new thread completes.
// Also facilitates data races.
std::vector<...> v;
std::thread([&v] () {
// use/modify v
});
// BETTER: v is moved to be "owned" by the
// closure, so it will certainly live as long as the
// thread is alive.
std::vector<...> v;
std::thread([v=std::move(v)] () mutable {
// use/modify v
})
There's really no such thing as a member function that takes this as moved in C++, but there is in Rust. You can think of it as a static class method that looks like this instead:
static void thr(TimerQueue &&tq);
// called as
TimerQueue::thr(std::move(tq));
Of course, that's not identical to the Rust version in many ways, but hopefully this helps you understand what's going on.
That error message is certainly unhelpful. Not sure what's going on there.

How to store JoinHandle of a thread to close it later [duplicate]

This question already has answers here:
Cannot move out of borrowed content / cannot move out of behind a shared reference
(1 answer)
Cannot move out of borrowed content when trying to transfer ownership
(1 answer)
Closed 3 years ago.
I am trying to run a thread in background and then change an AtomicBool to ask the thread to stop. To ensure the thread stopped properly, I want to call join method of the JoinHandle.
Instead of calling join, if I just wait (thread::sleep_ms) for sometime after setting the AtomicBool, the thread properly closes. But to ensure this I want to use join.
Or is there any better method to ensure the thread closed properly?
use std::sync::Arc;
use std::sync::Mutex;
use std::sync::atomic::{AtomicBool, Ordering};
use std::thread;
use std::thread::JoinHandle;
struct MyInner { s: String }
struct My {
inner: Arc<Mutex<MyInner>>,
close_thread: Arc<AtomicBool>,
my_thread: JoinHandle<()>
}
impl MyInner {
fn new(s: String) -> MyInner {
MyInner {
s: s
}
}
}
impl My {
fn new(s: String) -> My {
My {
inner: Arc::new(Mutex::new(MyInner::new(s))),
close_thread: Arc::new(AtomicBool::new(false)),
my_thread: thread::spawn(move || {})
}
}
fn stop_thread(&self) {
self.close_thread.swap(true, Ordering::Relaxed);
// ERROR!
self.my_thread.join().expect("Couldn't join my_thread on the main thread");
}
fn start(&mut self) {
let local_self = self.inner.clone();
let close_thread = self.close_thread.clone();
self.my_thread = thread::spawn(move || {
loop {
if close_thread.load(Ordering::Relaxed) {
println!("Closing thread!");
return;
}
let gaurd = local_self.lock().unwrap();
println!("Local self has value: {}", (*gaurd).s);
std::mem::drop(gaurd);
thread::sleep_ms(1000);
}
});
}
}
fn main() {
let mut m = My::new("blo".to_owned());
m.start();
thread::sleep_ms(2000);
m.stop_thread();
println!("Complete!");
}
For the above code, I get the error:
error[E0507]: cannot move out of `self.my_thread` which is behind a shared reference
--> src/main.rs:35:9
|
35 | self.my_thread.join().expect("Couldn't join my_thread on the main thread");
| ^^^^^^^^^^^^^^ move occurs because `self.my_thread` has type `std::thread::JoinHandle<()>`, which does not implement the `Copy` trait
I also tried using Arc on the JoinHandle but even after Arc::clone I get the same error.

Resources