How do I emulate a timer inside an object that will periodically mutate the object? - multithreading

In my project I need to do something like:
use std::thread;
use std::time::Duration;
struct A {
pub ints: Vec<u8>,
}
impl A {
fn new() -> A {
let mut a = A {
ints: vec![1, 5, 6, 2, 3, 4],
};
a.timer();
a
}
fn timer(&mut self) {
thread::spawn(move || {
loop {
thread::sleep(Duration::from_millis(1));
self.ints.remove(0);
}
});
}
}
fn main() {
let a = A::new();
loop {
println!("Remaining elements: {:?}", a.ints);
}
}
The idea is that some struct contains a vector of elements. These elements should be removed from the vector after some period of time. Think of it as a periodic timer that checks something and performs an action on mutable object (removes an element). This thread also needs to be dropped if the object on which it is working on is deleted. So I guess it should be a member of a struct of which it is manipulating.
The problem with the code above is that it has a lot of borrow errors and I don't understand how to do that.
I have seen few questions like this but each of them was about manipulating scalar in a thread. The reason why I can't apply it here is because the thread should be something that is inside A struct and it should call remove on a vector that is a member of that struct.
I guess I should use Arc or something like that but don't really understand how to use it here.

I guess I should use Arc or something like that but don't really understand how to use it here.
Indeed that is the simplest solution:
You can wrap the ints field in an Arc, but then you wouldn't be able to modify the Vec, so you also wrap it in a Mutex:
struct A {
pub ints: Arc<Mutex<Vec<u8>>>,
}
Then you can clone the Arc to receive a second handle to the same memory.
fn timer(&mut self) {
let ints = self.ints.clone();
thread::spawn(move || {
loop {
thread::sleep(Duration::from_millis(1));
Instead of directly accessing the Vec, you then need to lock the Mutex, which can fail if another thread panicked while accessing the Mutex.
ints.lock().unwrap().remove(0);
}
});
}

Related

Rust: Using Mutex and Arc to mutate

I am trying to allow multiple threads to mutate the same variable using Arc and a Mutex lock, but it seems as though I am unable to get ownership of the variable, even after cloning it?
// modifed example from https://doc.rust-lang.org/beta/rust-by-example/std/arc.html
use std::sync::{Arc, Mutex};
use std::thread;
use std::time::Duration;
fn main() {
// This variable declaration is where its value is specified.
let test = Arc::new(Mutex::new(TestStruct{
counter: 0,
}));
println!("Initial Counter Value: 0");
for _ in 0..10 {
// Here there is no value specification as it is a pointer to a
// reference in the memory heap.
let test = Arc::clone(&test);
thread::spawn(move || {
// As Arc was used, threads can be spawned using the value allocated
// in the Arc variable pointer's location.
test.lock().unwrap().increment();
});
}
// Make sure all Arc instances are printed from spawned threads.
thread::sleep(Duration::from_secs(1));
println!("Final Counter Value: {:?}", test.lock().unwrap().counter);
}
#[derive(Debug)]
struct TestStruct {
// counter
counter: i32,
}
impl TestStruct {
// increment counter
fn increment(mut self) {
self.counter +=1;
}
}
I keep getting errors that say error[E0507]: cannot move out of dereference of "MutexGuard<"_, TestStruct> anywhere that I try to access the variable with test.lock().unwrap()
All I am trying to do in this example is increment a counter from multiple threads, and then check the value of this counter afterwards.
I've gotten it to work by placing the value inside of an option: Arc::new(Mutex::new(Some(TestStruct{..}))) and then taking the value from that option: test.lock().unwrap().take(), but taking the value out of the Option then replaces it with None, so it only works once.
Does anyone know what I am doing wrong / how I might be able to get this to work?
Here is a link to a playground with the code.
Since you take mut self as opposed to &mut self in increment you need to exclusively own the variable to use it.
But you can only take references to objects in Arc<Mutex<…>>.
You probably want to take self by mutable reference in increment instead:
impl TestStruct {
// increment counter
fn increment(&mut self) {
self.counter +=1;
}
}

Unsafely define struct to share mutable references between threads

I need to unsafely define a Rust struct that I can share between 2 threads and mutate the content of the struct from both threads.
I do not want to use Mutex nor RwLock because I want to implement the thread safety myself. For performance concerns, I do not want to check the mutex when time I want to access the content and I know it is not in the critical section.
If I only use Arc to share the struct between threads, I get cannot borrow data in an Arc as mutable and help: trait DerefMut is required to modify through a dereference, but it is not implemented for std::sync::Arc<Foo>.
The safe way to do this:
struct Foo {
bar: usize,
}
impl Foo {
pub fn set_bar(&mut self, a: usize) {
self.bar = a;
}
}
fn main() {
let mut foo = Foo { bar: 32 };
foo.bar = 33;
let foo_arc = std::sync::Arc::new(std::sync::Mutex::new(foo));
let foo_arc_2 = std::sync::Arc::clone(&foo_arc);
let handle = std::thread::spawn(move || {
foo_arc_2.lock().unwrap().set_bar(32);
});
foo_arc.lock().unwrap().set_bar(31);
handle.join().unwrap();
}
What I unsafely want to achieve:
struct Foo {
bar: usize,
// My own lock
// lock: std::sync::Mutex<usize>,
}
unsafe impl Sync for Foo {}
impl Foo {
pub fn set_bar(&mut self, a: usize) {
self.bar = a;
}
}
fn main() {
let mut foo = Foo { bar: 32 };
foo.bar = 33;
let foo_arc = std::sync::Arc::new(foo);
let foo_arc_2 = std::sync::Arc::clone(&foo_arc);
let handle = std::thread::spawn(move || {
foo_arc_2.set_bar(32);
});
foo_arc.set_bar(31);
handle.join().unwrap();
}
I might not have to use Arc and use something more low level unknown to me at the moment.
If you want to do this to later use it in production, don't do it! Many people smarter than you and me already done this correctly. Use what they wrote instead. If you want to do this as an exercise, or for learning purposes, then go ahead and do it.
If you want to provide a type with interior mutability then you must use UnsafeCell. This type is at a core of every interior mutability in rust and using it is the only way to get a &mut T from &T. You should read really carefully it's documentation, the documentation of the cell module and The Nomicon (preferably all of it, but at least concurrency chapter).
If you prefer watching videos, Jon Gjengset has, among many others, this amazing video on cell types. And this video on atomic memory and implementing (bad) mutex.

What is the right smart pointer to have multiple strong references and allow mutability?

I want to have a structure on the heap with two references; one for me and another from a closure. Note that the code is for the single-threaded case:
use std::rc::Rc;
#[derive(Debug)]
struct Foo {
val: u32,
}
impl Foo {
fn set_val(&mut self, val: u32) {
self.val = val;
}
}
impl Drop for Foo {
fn drop(&mut self) {
println!("we drop {:?}", self);
}
}
fn need_callback(mut cb: Box<FnMut(u32)>) {
cb(17);
}
fn create() -> Rc<Foo> {
let rc = Rc::new(Foo { val: 5 });
let weak_rc = Rc::downgrade(&rc);
need_callback(Box::new(move |x| {
if let Some(mut rc) = weak_rc.upgrade() {
if let Some(foo) = Rc::get_mut(&mut rc) {
foo.set_val(x);
}
}
}));
rc
}
fn main() {
create();
}
In the real code, need_callback saves the callback to some place, but before that may call cb as need_callback does.
The code shows that std::rc::Rc is not suitable for this task because foo.set_val(x) is never called; I have two strong references and Rc::get_mut gives None in this case.
What smart pointer with reference counting should I use instead of std::rc::Rc to make it possible to call foo.set_val? Maybe it is possible to fix my code and still use std::rc::Rc?
After some thinking, I need something like std::rc::Rc, but weak references should prevent dropping. I can have two weak references and upgrade them to strong when I need mutability.
Because it is a singled-threaded program, I will have only strong reference at a time, so everything will work as expected.
Rc (and its multithreaded counterpart Arc) only concern themselves with ownership. Instead of a single owner, there is now joint ownership, tracked at runtime.
Mutability is a different concept, although closely related to ownership: if you own a value, then you have the ability to mutate it. This is why Rc::get_mut only works when there is a single strong reference - it's the same as saying there is a single owner.
If you need the ability to divide mutability in a way that doesn't match the structure of the program, you can use tools like Cell or RefCell for single-threaded programs:
use std::cell::RefCell;
fn create() -> Rc<RefCell<Foo>> {
let rc = Rc::new(RefCell::new(Foo { val: 5 }));
let weak_rc = Rc::downgrade(&rc);
need_callback(move |x| {
if let Some(rc) = weak_rc.upgrade() {
rc.borrow_mut().set_val(x);
}
});
rc
}
Or Mutex, RwLock, or an atomic type in multithreaded contexts:
use std::sync::Mutex;
fn create() -> Rc<Mutex<Foo>> {
let rc = Rc::new(Mutex::new(Foo { val: 5 }));
let weak_rc = Rc::downgrade(&rc);
need_callback(move |x| {
if let Some(rc) = weak_rc.upgrade() {
if let Ok(mut foo) = rc.try_lock() {
foo.set_val(x);
}
}
});
rc
}
These tools all defer the check that there is only a single mutable reference to runtime, instead of compile time.

Generate sequential IDs for each instance of a struct

I'm writing a system where I have a collection of Objects, and each Object has a unique integral ID. Here's how I would do it in C++:
class Object {
public:
Object(): id_(nextId_++) { }
private:
int id_;
static int nextId_;
}
int Object::nextId_ = 1;
This is obviously not thread_safe, but if I wanted it to be, I could make nextId_ an std::atomic_int, or wrap a mutex around the nextId_++ expression.
How would I do this in (preferably safe) Rust? There's no static struct members, nor are global mutable variables safe. I could always pass nextId into the new function, but these objects are going to be allocated in a number of places, and I would prefer not to pipe the nextId number hither and yon. Thoughts?
Atomic variables can live in statics, so you can use it relatively straightforwardly (the downside is that you have global state).
Example code: (playground link)
use std::{
sync::atomic::{AtomicUsize, Ordering},
thread,
};
static OBJECT_COUNTER: AtomicUsize = AtomicUsize::new(0);
#[derive(Debug)]
struct Object(usize);
impl Object {
fn new() -> Self {
Object(OBJECT_COUNTER.fetch_add(1, Ordering::SeqCst))
}
}
fn main() {
let threads = (0..10)
.map(|_| thread::spawn(|| Object::new()))
.collect::<Vec<_>>();
for t in threads {
println!("{:?}", t.join().unwrap());
}
}
nor are global mutable variables safe
Your C++ example seems like it would have thread-safety issues, but I don't know enough C++ to be sure.
However, only unsynchronized global mutable variables are trouble. If you don't care about cross-thread issues, you can use a thread-local:
use std::cell::Cell;
#[derive(Debug)]
struct Monster {
id: usize,
health: u8,
}
thread_local!(static MONSTER_ID: Cell<usize> = Cell::new(0));
impl Monster {
fn new(health: u8) -> Monster {
MONSTER_ID.with(|thread_id| {
let id = thread_id.get();
thread_id.set(id + 1);
Monster { id, health }
})
}
}
fn main() {
let gnome = Monster::new(41);
let troll = Monster::new(42);
println!("gnome {:?}", gnome);
println!("troll {:?}", troll);
}
If you do want something that works better with multiple threads, check out bluss' answer, which shows how to use an atomic variable.

Copying a struct for use on another thread

I have a struct:
struct MyData {
x: i32
}
I want to asynchronously start a long operation on this struct.
My first attempt was this:
fn foo(&self) { //should return immediately
std::thread::Thread::spawn(move || {
println!("{:?}",self.x); //consider a very long operation
});
}
Clearly the compiler cannot infer an appropriate lifetime due to conflicting requirements because self may be on the stack frame and thus cannot be guaranteed to exist by the time the operation is running on a different stack frame.
To solve this, I attempted to make a copy of self and provide that copy to the new thread:
fn foo(&self) { //should return immediately
let clone = self.clone();
std::thread::Thread::spawn(move || {
println!("{:?}",clone.x); //consider a very long operation
});
}
I think that does not compile because now clone is on the stack frame which is similar to before. I also tried to do the clone inside the thread, and that does not compile either, I think for similar reasons.
Then I decided maybe I could use a channel to push the copied data into the thread, on the theory that perhaps channel can magically move (copy?) stack-allocated data between threads, which is suggested by this example in the documentation. However the compiler cannot infer a lifetime for this either:
fn foo(&self) { //should return immediately
let (tx, rx) = std::sync::mpsc::channel();
tx.send(self.clone());
std::thread::Thread::spawn(move || {
println!("{:?}",rx.recv().unwrap().x); //consider a very long operation
});
}
Finally, I decided to just copy my struct onto the heap explicitly, and pass an Arc into the thread. But not even here can the compiler figure out a lifetime:
fn foo(&self) { //should return immediately
let arc = std::sync::Arc::new(self.clone());
std::thread::Thread::spawn(move || {
println!("{:?}",arc.clone().x); //consider a very long operation
});
}
Okay borrow checker, I give up. How do I get a copy of self onto my new thread?
I think your issue is simply because your structure does not derive the Clone trait. You can get your second example to compile and run by adding a #[derive(Clone)] before your struct's definition.
What I don't understand in the compiler behaviour here is what .clone() function it tried to use here. Your structure indeed did not implement the Clone trait so should not by default have a .clone() function.
playpen
You may also want to consider in your function taking self by value, and let your caller decide whether it should make a clone, or just a move.
As an alternative solution, you could use thread::scoped and maintain a handle to the thread. This allows the thread to hold a reference, without the need to copy it in:
#![feature(old_io,std_misc)]
use std::thread::{self,JoinGuard};
use std::old_io::timer;
use std::time::duration::Duration;
struct MyData {
x: i32,
}
// returns immediately
impl MyData {
fn foo(&self) -> JoinGuard<()> {
thread::scoped(move || {
timer::sleep(Duration::milliseconds(300));
println!("{:?}", self.x); //consider a very long operation
timer::sleep(Duration::milliseconds(300));
})
}
}
fn main() {
let d = MyData { x: 42 };
let _thread = d.foo();
println!("I'm so fast!");
}

Resources