2 votes

Passage de soi dans un fil

J'ai le code suivant :

use std::error::Error;
use std::collections::HashMap;
use std::fmt::{Display, Formatter, Error as FmtError};
use std::sync::{Arc, Mutex};
use std::thread;

use amiquip::{ConsumerMessage};
use serde::Deserialize;

use crate::rabbit_mq;
use crate::rabbit_mq::RmqChannel;
use super::agv::*;

pub type AGVControllerError = Box<dyn Error + Send + Sync + 'static>;
pub type AGVControllerResult<T> = Result<T, AGVControllerError>;

pub struct AGVController<'a> {
    agv_map: HashMap<&'a str, AGV>,
    //rmq: &'a mut rabbit_mq::RMQ
    rmq: Arc<Mutex<rabbit_mq::RMQ>>
}

impl<'a> AGVController<'a> {
    // Create a new AGV Controller
    //pub fn new(rmq: &'a mut rabbit_mq::RMQ) -> Self {
    pub fn new(rmq: Arc<Mutex<rabbit_mq::RMQ>>) -> Self {
        Self {
            agv_map: HashMap::new(),
            rmq
        }
    }

    // Listen for messages related to the agv controller.
    pub fn listen(&'static mut self, routing_key: &'static str) -> AGVControllerResult<()> {
        let mut rmq_channel = self.rmq.lock().unwrap().create_channel()?;

        thread::spawn(move || {
            //TODO: need to handle any error returned here
            //listen_on_consumer(routing_key, rmq_channel).unwrap();
            let consumer = rmq_channel.create_consumer(routing_key).unwrap();
            let test = self.agv_map.get("rr");
            for (i, message) in consumer.receiver().iter().enumerate() {
                match message {
                    ConsumerMessage::Delivery(delivery) => {
                        let body = String::from_utf8_lossy(&delivery.body);
                        println!("({:>3}) Received [{}]", i, body);
                        consumer.ack(delivery).unwrap();
                    }
                    other => {
                        println!("Consumer ended: {:?}", other);
                        break;
                    }
                }
            }
        });

        return Ok(());
    }
}

Dans la fonction d'écoute, je crée un consommateur de rmq et je lis les messages au fur et à mesure qu'ils arrivent. Tout cela fonctionne bien. Mais lorsqu'un message est lu, j'ai besoin d'accéder aux informations, données et fonctions de la structure. Faire en sorte que le paramètre self utilise 'static' semble régler le problème. Est-ce correct ? static signifie qu'il reste en vie aussi longtemps que le programme existe, n'est-ce pas ? Ce qui semble correct puisque je veux qu'il soit vivant tant que le fil de discussion est en cours. Je veux juste m'assurer que je fais cela correctement.

UPDATE :

J'ai donc essayé de me cloner et de l'utiliser dans le fil de discussion mais j'obtiens :

error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
   --> src/agv/agv_controller.rs:47:35
    |
47  |         let mut self_clone = self.clone();
    |                                   ^^^^^
    |
note: first, the lifetime cannot outlive the lifetime `'a` as defined here...
   --> src/agv/agv_controller.rs:35:6
    |
35  | impl<'a> AGVController<'a> {
    |      ^^
note: ...so that the types are compatible
   --> src/agv/agv_controller.rs:47:35
    |
47  |         let mut self_clone = self.clone();
    |                                   ^^^^^
    = note: expected `&agv_controller::AGVController<'_>`
               found `&agv_controller::AGVController<'a>`
    = note: but, the lifetime must be valid for the static lifetime...
note: ...so that the type `[closure@src/agv/agv_controller.rs:48:23: 66:10]` will meet its required lifetime bounds...
   --> src/agv/agv_controller.rs:48:9
    |
48  |         thread::spawn(move || {
    |         ^^^^^^^^^^^^^
note: ...that is required by this bound
   --> /Users/conordowney/.rustup/toolchains/nightly-aarch64-apple-darwin/lib/rustlib/src/rust/library/std/src/thread/mod.rs:646:15
    |
646 |     F: Send + 'static,
    |               ^^^^^^^

0voto

jeremymeadows Points 46

J'ai dû massacrer votre programme pour qu'il compile sur ma machine (pour référence future, une exemple minimal reproductible que l'on peut faire tomber dans une cour de récréation est super utile), mais je pense avoir trouvé la cause première.

Il n'a pas aimé que vous essayiez de passer quelque chose à l'intérieur d'une Mutex dans un autre fil de discussion, vous devez donc cloner le fichier Arc (son but principal est d'être cloné), puis verrouillez-le dans le fil.

Je ne peux pas dire ce qu'un AGV mais il semble que vous ne lisez que la carte, donc avec un peu de chance le unwrap/deref permet de la déplacer en toute sécurité. Si vous avez besoin de la carte entière, vous devriez pouvoir substituer un appel à .clone() .

use std::error::Error;
use std::collections::HashMap;
use std::fmt::{Display, Formatter, Error as FmtError};
use std::sync::{Arc, Mutex};
use std::thread;

use amiquip::{ConsumerMessage};
use serde::Deserialize;

use crate::rabbit_mq{self, RmqChannel};
use super::agv::*;

pub type AGVControllerError = Box<dyn Error + Send + Sync + 'static>;
pub type AGVControllerResult<T> = Result<T, AGVControllerError>;

pub struct AGVController<'a> {
    agv_map: HashMap<&'a str, AGV>,
    rmq: Arc<Mutex<rabbit_mq::RMQ>>
}

impl<'a> AGVController<'a> {
    // Create a new AGV Controller
    pub fn new(rmq: Arc<Mutex<rabbit_mq::RMQ>>) -> Self {
        Self {
            agv_map: HashMap::new(),
            rmq
        }
    }

    // Listen for messages related to the agv controller.
    pub fn listen(&self, routing_key: &'static str) -> AGVControllerResult<()> {
        //let mut rmq_channel = self.rmq.lock().unwrap().create_channel()?;
        let rmq_channel_mtx = self.rmq.clone();
        let rr = *self.agv_map.get("rr").unwrap()

        thread::spawn(move || {
            let rmq_channel = rmq_channel_mtx.lock().unwrap();
            let consumer = rmq_channel.create_consumer(routing_key).unwrap();

            let test = rr;

            for (i, message) in consumer.receiver().iter().enumerate() {
                match message {
                    ConsumerMessage::Delivery(delivery) => {
                        let body = String::from_utf8_lossy(&delivery.body);
                        println!("({:>3}) Received [{}]", i, body);
                        consumer.ack(delivery).unwrap();
                    }
                    other => {
                        println!("Consumer ended: {:?}", other);
                        break;
                    }
                }
            }
        });

        return Ok(());
    }
}

Remarque, à moins que vous ayez vraiment besoin d'un &str je trouve qu'il est généralement plus facile de traiter avec les propriétaires. String dans des structures telles que HashMap De plus, vous n'aurez pas besoin de ces annotations à vie partout.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X