How do I change the structure in the thread? - multithreading

Please help me, I'm completely confused.
How do I make this code work?
I need to change the structure members in the thread...
#[derive(Debug)]
struct S {
str: String,
b: bool,
i: u128,
}
fn main() {
let mut vec_s = vec![];
vec_s.push(S {
str: "a".to_string(),
b: false,
i: 0,
});
let mut threads = vec![];
for s in vec_s {
{
let mut _s = &s;
threads.push(std::thread::spawn(move || {
_s.b = true;
_s.str = "b".to_string();
_s.i = 1;
}));
}
}
for thread in threads {
let _ = thread.join();
}
dbg!(&vec_s);
}
The compiler outputs a lot of errors:
error[E0594]: cannot assign to `_s.b`, which is behind a `&` reference
--> src/main.rs:23:17
|
23 | _s.b = true;
| ^^^^^^^^^^^ cannot assign
error[E0594]: cannot assign to `_s.str`, which is behind a `&` reference
--> src/main.rs:24:17
|
24 | _s.str = "b".to_string();
| ^^^^^^ cannot assign
error[E0594]: cannot assign to `_s.i`, which is behind a `&` reference
--> src/main.rs:25:17
|
25 | _s.i = 1;
| ^^^^^^^^ cannot assign
error[E0597]: `s` does not live long enough
--> src/main.rs:21:26
|
21 | let mut _s = &s;
| ^^ borrowed value does not live long enough
22 | threads.push(std::thread::spawn(move || {
| __________________________-
23 | | _s.b = true;
24 | | _s.str = "b".to_string();
25 | | _s.i = 1;
26 | | }));
| |______________- argument requires that `s` is borrowed for `'static`
27 | }
28 | }
| - `s` dropped here while still borrowed
error[E0382]: borrow of moved value: `vec_s`
--> src/main.rs:34:10
|
9 | let mut vec_s = vec![];
| --------- move occurs because `vec_s` has type `Vec<S>`, which does not implement the `Copy` trait
...
19 | for s in vec_s {
| ----- `vec_s` moved due to this implicit call to `.into_iter()`
...
34 | dbg!(&vec_s);
| ^^^^^^ value borrowed here after move
|
note: this function takes ownership of the receiver `self`, which moves `vec_s`
--> /home/martin/.rustup/toolchains/stable-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/iter/traits/collect.rs:261:18
|
261 | fn into_iter(self) -> Self::IntoIter;
| ^^^^
help: consider iterating over a slice of the `Vec<S>`'s content to avoid moving into the `for` loop
|
19 | for s in &vec_s {
| +

You are attempting to do multithreading. Everything accessed by multiple threads has to be thread-safe. Further, with Rust being very strict (zero undefined behaviour tolerance), the compiler has to understand that your code is thread-safe.
The biggest problem here is that Rust's borrow checker doesn't understand that your threads get joined at some point. Therefore it doesn't allow you to create references to your S objects, because it cannot prove how long those references exist. Rust must be able to prove that they are destroyed before your S object is dropped; that's part of Rust's borrow checker safety guarantees.
For your specific usecase, Rust introduced thread scopes. With them, the compiler can finally understand thread lifetimes.
With some minor ownership issues fixed (use &mut vec_s for your loop, otherwise the vec_s object gets consumed by the loop), this now works:
#[derive(Debug)]
struct S {
s: String,
b: bool,
i: u128,
}
fn main() {
let mut vec_s = vec![];
vec_s.push(S {
s: "a".to_string(),
b: false,
i: 0,
});
std::thread::scope(|scope| {
let mut threads = vec![];
for s in &mut vec_s {
threads.push(scope.spawn(move || {
s.b = true;
s.s = "b".to_string();
s.i = 1;
}));
}
for thread in threads {
let _ = thread.join();
}
});
dbg!(&vec_s);
}
[src/main.rs:31] &vec_s = [
S {
s: "b",
b: true,
i: 1,
},
]
Another optimization:
If you don't actually use the JoinHandles for error propagation or similar, you don't need them at all in this example. The scope already automatically joins all threads it spawned at the end of the scope:
#[derive(Debug)]
struct S {
s: String,
b: bool,
i: u128,
}
fn main() {
let mut vec_s = vec![];
vec_s.push(S {
s: "a".to_string(),
b: false,
i: 0,
});
std::thread::scope(|scope| {
for s in &mut vec_s {
scope.spawn(move || {
s.b = true;
s.s = "b".to_string();
s.i = 1;
});
}
});
dbg!(&vec_s);
}
[src/main.rs:27] &vec_s = [
S {
s: "b",
b: true,
i: 1,
},
]

Related

How do I move a vector reference into threads? [duplicate]

This question already has an answer here:
How can I pass a reference to a stack variable to a thread?
(1 answer)
Closed last month.
How do I move a vector reference into threads? The closest I get is the (minimized) code below. (I realize that the costly calculation still isn't parallel, as it is locked by the mutex, but one problem at a time.)
Base problem: I'm calculating values based on information saved in a vector. Then I'm storing the results as nodes per vector element. So vector in vector (but only one vector in the example code below). The calculation takes time so I would like to divide it into threads. The structure is big, so I don't want to copy it.
use std::sync::{Arc, Mutex};
use std::thread;
fn main() {
let n = Nodes::init();
n.calc();
println!("Result: nodes {:?}", n);
}
#[derive(Debug)]
struct Nodes {
nodes: Vec<Info>,
}
impl Nodes {
fn init() -> Self {
let mut n = Nodes { nodes: Vec::new() };
n.nodes.push(Info::init(1));
n.nodes.push(Info::init(2));
n
}
fn calc(&self) {
Nodes::calc_associative(&self.nodes);
}
fn calc_associative(nodes: &Vec<Info>) {
let mut handles = vec![];
let arc_nodes = Arc::new(nodes);
let counter = Arc::new(Mutex::new(0));
for _ in 0..2 {
let arc_nodes = Arc::clone(&arc_nodes);
let counter = Arc::clone(&counter);
let handle = thread::spawn(move || {
let mut idx = counter.lock().unwrap();
// costly calculation
arc_nodes[*idx].set_length(arc_nodes[*idx].get_length() * 2);
*idx += 1;
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
}
}
#[derive(Debug)]
struct Info {
length: u32,
}
impl Info {
fn init(length: u32) -> Self {
Info { length }
}
fn get_length(&self) -> u32 {
self.length
}
fn set_length(&mut self, x: u32) {
self.length = x;
}
}
The compiler complains that life time of the reference isn't fulfilled, but isn't that what Arc::clone() should do? Then Arc require a deref, but maybe there are better solutions before starting to dig into that...?
Compiling threads v0.1.0 (/home/freefox/proj/threads)
error[E0596]: cannot borrow data in an `Arc` as mutable
--> src/main.rs:37:17
|
37 | arc_nodes[*idx].set_length(arc_nodes[*idx].get_length() * 2);
| ^^^^^^^^^ cannot borrow as mutable
|
= help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Arc<&Vec<Info>>`
error[E0521]: borrowed data escapes outside of associated function
--> src/main.rs:34:26
|
25 | fn calc_associative(nodes: &Vec<Info>) {
| ----- - let's call the lifetime of this reference `'1`
| |
| `nodes` is a reference that is only valid in the associated function body
...
34 | let handle = thread::spawn(move || {
| __________________________^
35 | | let mut idx = counter.lock().unwrap();
36 | | // costly calculation
37 | | arc_nodes[*idx].set_length(arc_nodes[*idx].get_length() * 2);
38 | | *idx += 1;
39 | | });
| | ^
| | |
| |______________`nodes` escapes the associated function body here
| argument requires that `'1` must outlive `'static`
Some errors have detailed explanations: E0521, E0596.
For more information about an error, try `rustc --explain E0521`.
error: could not compile `threads` due to 2 previous errors
You wrap a reference with Arc. Now the type is Arc<&Vec<Info>>. There is still a reference here, so the variable could still be destroyed before the thread return and we have a dangling reference.
Instead, you should take a &Arc<Vec<Info>>, and on the construction of the Vec wrap it in Arc, or take &[Info] and clone it (let arc_nodes = Arc::new(nodes.to_vec());). You also need a mutex along the way (either Arc<Mutex<Vec<Info>>> or Arc<Vec<Mutex<Info>>>), since you want to change the items.
Or better, since you immediately join() the threads, use scoped threads:
fn calc_associative(nodes: &[Mutex<Info>]) {
let counter = std::sync::atomic::AtomicUsize::new(0); // Changed to atomic, prefer it to mutex wherever possible
std::thread::scope(|s| {
for _ in 0..2 {
s.spawn(|| {
let idx = counter.fetch_add(1, std::sync::atomic::Ordering::SeqCst);
let node = &mut *nodes[idx].lock().unwrap();
// costly calculation
node.set_length(node.get_length() * 2);
});
}
});
}

Rust assignment and use borrow at the same time

It confuses me that the error at line A has anything to do with line C, as they basically appear in different branches?
pub struct ListNode {
pub val: i32,
pub next: Option<Box<ListNode>>
}
pub fn foo(mut head: Option<Box<ListNode>>) -> Option<Box<ListNode>> {
let mut p1 = head.as_mut()?;
if let Some(p2) = p1.next.as_mut() {
if true {
p1.next = None; // A: Error here if C is not commented out
} else {
// p1.next = None; // B
p1 = p2; // C: No error on this line
}
}
head
To make things worse, the error has code E0506, suggesting an attempt is made to assign a borrowed value (p1.next). How come I cannot assign this borrowed value (which I believe is mutably borrowed) now but I can do that simply by deleting line C?
error[E0506]: cannot assign to `p1.next` because it is borrowed
--> src/remove_dup.rs:11:13
|
9 | if let Some(p2) = p1.next.as_mut() {
| ------- borrow of `p1.next` occurs here
10 | if true {
11 | p1.next = None; // A: Error happnens here if C is not commented out
| ^^^^^^^
| |
| assignment to borrowed `p1.next` occurs here
| borrow later used here

Rust borrow checker multiple mutable reference in modifying element in linked list in a loop

I'm trying to build some sort of linked list, each node has a keyword and vectors of the same node. In that for loop, i will traverse the linked list to get the vector, either already exist if keyword is the same, or create a new vector. I find it impossible to *not * violate the double mut reference error since I'll need to do iter_mut(), push() on the same path. Anyone has general idea on how to approach this?
pub struct Knowledge {
pub title: String,
}
pub struct Entry {
pub keyword: String,
pub next: Vec<Box<KnowledgeEntry>>
}
pub enum KnowledgeEntry {
Normal(Knowledge),
Entry(Entry)
}
impl KnowledgeEntry {
pub fn get_entry_mut (&mut self) -> Option<&mut Vec<Box<KnowledgeEntry>>> {
match self {
KnowledgeEntry::Entry(e) => {
Some(&mut e.next)
}
KnowledgeEntry::Normal(k) => {None}
}
}
}
fn main () {
let mut entry = Entry{keyword: "".to_owned(), next: vec![]};
let mut current_container = &mut entry.next;
let new_knowledge = Knowledge{title: "title1".to_owned()};
// new knowledge to be insert in these hierarchy.
let remaining_comp: Vec<_> = vec!["hier1", "hier2", "hier3"];
// each loop will set current_container, either created from new, or found in the vector.
for comp in remaining_comp.iter() {
// true will be replace with body checking with keyword.
let mut _result = current_container.iter_mut().find(|en| {true});
if let Some(mut _res) = _result {
// found the container. Set the current container
if let KnowledgeEntry::Entry(ref mut entry) = &mut **_res {
current_container = &mut entry.next;
} else {
break;
}
} else {
// can't find the resulting container. Create a new vector, and move the container.
let new_container: Vec<Box<KnowledgeEntry>> = vec![];
let mut _temp = KnowledgeEntry::Entry(Entry {
keyword: (*comp).to_string(),
next: new_container
});
current_container.push(Box::new(_temp));
let last_var = current_container.last_mut().unwrap();
// get_entry_mut() to retrieve `_temp` that we have just moved.
current_container = (**last_var).get_entry_mut().unwrap();
}
}
// found the container correspond to "hier1" -> "hier2" -> "hier3", add the entry.
current_container.push(Box::new(KnowledgeEntry::Normal(new_knowledge)));
}
Playground
Produces the following errors:
error[E0499]: cannot borrow `*current_container` as mutable more than once at a time
--> src/main.rs:50:13
|
35 | let mut _result = current_container.iter_mut().find(|en| {true});
| ----------------- first mutable borrow occurs here
...
50 | current_container.push(Box::new(_temp));
| ^^^^^^^^^^^^^^^^^
| |
| second mutable borrow occurs here
| first borrow later used here
error[E0499]: cannot borrow `*current_container` as mutable more than once at a time
--> src/main.rs:51:28
|
35 | let mut _result = current_container.iter_mut().find(|en| {true});
| ----------------- first mutable borrow occurs here
...
51 | let last_var = current_container.last_mut().unwrap();
| ^^^^^^^^^^^^^^^^^
| |
| second mutable borrow occurs here
| first borrow later used here
error[E0499]: cannot borrow `*current_container` as mutable more than once at a time
--> src/main.rs:57:1
|
35 | let mut _result = current_container.iter_mut().find(|en| {true});
| ----------------- first mutable borrow occurs here
...
57 | current_container.push(Box::new(KnowledgeEntry::Normal(new_knowledge)));
| ^^^^^^^^^^^^^^^^^
| |
| second mutable borrow occurs here
| first borrow later used here

Accessing a method of self inside a thread in Rust

I want to propagate the self struct object into a thread and then call its time_tick() method for increasing the HMS time.
pub fn start(&mut self) {
self.acti = true; // the time tick is activated now...
thread::spawn(move || {
let local_self: *mut Self = self; // this self live in the thread
loop {
thread::sleep(Duration::from_secs(1)); // wait for 1 sec
if (*local_self).acti == true { (*local_self).time_tick(); }
(*local_self).print_time(); // for debug
}
});
}
I get the error message:
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
--> src/hmstimer/mod.rs:42:17
|
42 | thread::spawn(move || {
| _______________________^
43 | | let local_self: *mut Self = self; // this self live in the thread
44 | | loop {
45 | | thread::sleep(Duration::from_secs(1)); // wait for 1 sec
... |
48 | | }
49 | | });
| |_________^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 40:2...
--> src/hmstimer/mod.rs:40:2
|
40 | pub fn start(&mut self) {
| _____^
41 | | self.acti = true; // the time tick is activated now...
42 | | thread::spawn(move || {
43 | | let local_self: *mut Self = self; // this self live in the thread
... |
49 | | });
50 | | }
| |_____^
= note: ...so that the types are compatible:
expected &mut hmstimer::HMSTimer
found &mut hmstimer::HMSTimer
= note: but, the lifetime must be valid for the static lifetime...
note: ...so that the type `[closure#src/hmstimer/mod.rs:42:17: 49:7 self:&mut hmstimer::HMSTimer]` will meet its required lifetime bounds
But it seems that the about method is inappropriate. What is the best practice for doing the task?
You can't pass a closure that captures a mutable reference to thread::spawn. thread::spawn needs the function to be 'static, which means that either it captures no borrows, or that all borrows are 'static. That's because the thread can continue running after the referent has been dropped.
If you don't need to use self in the original thread after calling start, then you can just pass self by value.
pub fn start(self) {
self.acti = true;
thread::spawn(move || {
loop {
thread::sleep(Duration::from_secs(1));
if self.acti == true { self.time_tick(); }
self.print_time();
}
});
}
Otherwise, you'll need to use Arc to get the two threads to share ownership of Self, as well as Mutex or RwLock to synchronize reads and writes across threads.
// note: this is not a method anymore;
// invoke as `HMSTimer::start(arc.clone());`
pub fn start(this: Arc<Mutex<Self>>) {
this.lock().expect("mutex is poisoned").acti = true;
thread::spawn(move || {
loop {
thread::sleep(Duration::from_secs(1));
let lock = this.lock().expect("mutex is poisoned");
if lock.acti == true { lock.time_tick(); }
lock.print_time();
// `lock` is dropped here, unlocking the mutex
}
});
}

How do I conditionally choose between two fields of a struct and then update the chosen one?

I have two structs of the same type inside a larger struct. I will select one of the structs and perform updates using the same code.
A simplified version:
#[derive(Debug)]
struct Counts {
value: u16,
count: u8,
}
#[derive(Debug)]
struct Partitioned {
even: Counts,
odd: Counts,
}
fn sort() -> Partitioned {
let mut even = Counts { value: 2, count: 0 };
let mut odd = Counts { value: 3, count: 0 };
for i in 1..30 {
let mut s = if i % 2 == 0 { even } else { odd };
s.count = s.count + 1;
// ... a lot of other code
}
Partitioned { even, odd }
}
fn main() {
println!("{:?}", sort());
}
This does not compile with complaints about ownership:
error[E0382]: use of moved value: `even`
--> src/main.rs:19:37
|
19 | let mut s = if i % 2 == 0 { even } else { odd };
| ^^^^ value moved here in previous iteration of loop
|
= note: move occurs because `even` has type `Counts`, which does not implement the `Copy` trait
error[E0382]: use of moved value: `odd`
--> src/main.rs:19:51
|
19 | let mut s = if i % 2 == 0 { even } else { odd };
| ^^^ value moved here in previous iteration of loop
|
= note: move occurs because `odd` has type `Counts`, which does not implement the `Copy` trait
error[E0382]: use of moved value: `even`
--> src/main.rs:24:19
|
19 | let mut s = if i % 2 == 0 { even } else { odd };
| ---- value moved here
...
24 | Partitioned { even, odd }
| ^^^^ value used here after move
|
= note: move occurs because `even` has type `Counts`, which does not implement the `Copy` trait
error[E0382]: use of moved value: `odd`
--> src/main.rs:24:25
|
19 | let mut s = if i % 2 == 0 { even } else { odd };
| --- value moved here
...
24 | Partitioned { even, odd }
| ^^^ value used here after move
|
= note: move occurs because `odd` has type `Counts`, which does not implement the `Copy` trait
What is going on here? How can I implement it without copying all the update code to both blocks of the if?
Take a mutable reference to the field:
let mut s = if i % 2 == 0 { &mut even } else { &mut odd };

Resources