holo
November 15, 2019, 5:54am
1
I have such struct which i want to edit from threads:
pub struct Threaded {
servers: Vec<Server>,
pub commands: Vec<Command>,
commands_done: Vec<Command>,
}
Im trying to start threads in such way:
pub fn run(self) {
let data = Arc::new(Mutex::new(self));
// let data2 = Arc::new(Mutex::new(self.commands_done));
let (tx, rx) = channel();
self.servers.into_iter().for_each(|server| {
let (data, tx) = (Arc::clone(&data), tx.clone());
thread::spawn(move || {
server.execute(tx, data);
});
});
let mut commands_done: Vec<Command> = Vec::new();
loop {
let mut data = data.lock().unwrap();
...CUT
But im getting such error:
use of moved value: `self.servers`
value used here after move
When i will use instead of "self" in Arc "self.commands" everything is working but i do not have access to commands_done in threads.
I was trying to solve it with RefCell but without success is it correct way to handle such thing or maybe some other way?
alice
November 15, 2019, 6:08am
2
A RefCell cannot be used in a multithreaded context. Use a Mutex instead.
holo
November 15, 2019, 6:12am
3
Im using it but still can not read server field to start threads when i use whole struct in Arc. RefCell i was trying to use in such way:
ref = RefCell::new(self)
let data = Arc::new(Mutex::new(ref.borrow()));
ref.borrow().servers.into_iter().....CUT
But it did not work either. How such thing should be solved in Rust?
alice
November 15, 2019, 6:13am
4
Don't use a RefCell, you should put self directly into the Mutex.
holo
November 15, 2019, 6:16am
5
Im using it in mutex but after that i can not start threads with self.servers here:
self.servers.into_iter().for_each(|server| {
let (data, tx) = (Arc::clone(&data), tx.clone());
thread::spawn(move || {
server.execute(tx, data);
});
});
alice
November 15, 2019, 6:18am
6
Once you put self in an Arc<Mutex<...>>, you must access it through the Mutex. Perhaps you could do
let selfclone = Arc::clone(&Arc);
And create the Iterator through the Clone?
holo
November 15, 2019, 6:24am
7
I changed my code to:
let data = Arc::new(Mutex::new(self));
let (tx, rx) = channel();
let selfclone = Arc::clone(&data);
selfclone.servers.into_iter().for_each(|server| {
let (data, tx) = (Arc::clone(&data), tx.clone());
thread::spawn(move || {
server.execute(tx, data);
});
});
but right now im getting:
no field servers on type std::sync::Arc<std::sync::Mutex<threads::Threaded>>
unknown field
do i need to lock selfclone to access data?
EDIT:
Even with locking it still doesnt work:
let data = Arc::new(Mutex::new(self));
let (tx, rx) = channel();
let selfclone = Arc::clone(&data);
let locked = selfclone.lock().unwrap();
locked.servers.into_iter().for_each(|server| {
let (data, tx) = (Arc::clone(&data), tx.clone());
thread::spawn(move || {
server.execute(tx, data);
});
});
and im getting:
cannot move out of dereference of std::sync::MutexGuard<'_, threads::Threaded>
move occurs because value has type std::vec::Vec<server::Server>, which does not implement the Copy trait
alice
November 15, 2019, 6:33am
8
Using into_iter destroys the vector, which you can't on a shared item. Use iter to iterate references or drain to empty the vector while iterating it without destroying it.
1 Like
holo
November 15, 2019, 6:43am
9
With that change it still do not want to work, variables are not living enough:
selfclone does not live long enough
borrowed value does not live long enough
locked does not live long enough
borrowed value does not live long enough
pub fn run(self) {
let data = Arc::new(Mutex::new(self));
let (tx, rx) = channel();
let selfclone = Arc::clone(&data);
let locked = selfclone.lock().unwrap();
locked.servers.iter().for_each(|server| {
let (data, tx) = (Arc::clone(&data), tx.clone());
thread::spawn(move || {
server.execute(tx, data);
});
});
alice
November 15, 2019, 6:44am
10
Can you post the full errors?
alice
November 15, 2019, 6:45am
11
Actually I know, it's because you're trying to move server into a new thread, but since you used iter, it's a borrow and you can't move borrows into new threads like that. Use drain instead.
2 Likes
holo
November 15, 2019, 6:53am
12
Tank You for helping me, drain worked
Here is my working code:
let data = Arc::new(Mutex::new(self));
let (tx, rx) = channel();
let selfclone = Arc::clone(&data);
let mut locked = selfclone.lock().unwrap();
locked.servers.drain(..).for_each(|server| {
let (data, tx) = (Arc::clone(&data), tx.clone());
thread::spawn(move || {
server.execute(tx, data);
});
});
drop(selfclone);
1 Like
Yandros
November 15, 2019, 10:04am
13
Your spawned threads will start blocked by the mutex, you can avoid it using mem::replace rather than drain (so as to drop the lock guard before iterating, and at that point by just using mem::replace before commiting to Arc<Mutex<_>> locking is not even needed):
let servers = ::std::mem::replace(&mut self.servers, vec![]);
let data = Arc::new(Mutex::new(self));
let (tx, rx) = channel();
servers.into_iter().for_each(|server| {
let (data, tx) = (Arc::clone(&data), tx.clone());
thread::spawn(move || {
server.execute(tx, data);
});
});
2 Likes
system
Closed
February 13, 2020, 10:04am
14
This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.