Starting threads and moving struct

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?

A RefCell cannot be used in a multithreaded context. Use a Mutex instead.

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?

Don't use a RefCell, you should put self directly into the Mutex.

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);
        });
    });

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?

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

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

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);
    });
});

Can you post the full errors?

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

Tank You for helping me, drain worked :slight_smile:

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

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

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.