< 返回版块

recently-lxh 发表于 2023-09-01 18:25

rust新手:子线程中无法修改结构体里属性,提示borrowed data escapes outside of method。该怎么调整?查了很多帖子都没找到类似的解决方式

功能:

代码逻辑:

主要是server结构体中记录每个子线程中生成的流量日志记录.(模仿server服务端采集连接端最近30分钟流量使用信息)

里面涉及到一个自定义的环形链表数据结构,可以初始化大小,达到指定大小后,循环覆盖更新环形链表节点的信息。

错误信息:

borrowed data escapes outside of method
requirement occurs because of a mutable reference to `Server<'_>`
mutable references are invariant over their type parameter
see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variancerustcClick for full compiler diagnostic
traffic.rs(134, 14): `self` is a reference that is only valid in the method body
traffic.rs(134, 14): has type `&mut Server<'1>`
borrowed data escapes outside of method
`self` escapes the method body hererustcClick for full compiler diagnostic
traffic.rs(134, 14): `self` is a reference that is only valid in the method body
traffic.rs(134, 14): let's call the lifetime of this reference `'2`
borrowed data escapes outside of method
argument requires that `'2` must outlive `'static`rustcClick for full compiler diagnostic
traffic.rs(134, 14): `self` is a reference that is only valid in the method body
traffic.rs(134, 14): let's call the lifetime of this reference `'2`

下面是具体的简化后的代码逻辑:

use std::{cell::RefCell, sync::{Arc, Mutex}, collections::HashMap};

use chrono::Local;
#[allow(dead_code)]
struct LogNode<'a, K,V>{
    pub key:K,
    pub up:V,
    pub down:V,
    pub next:Option<Arc<RefCell<LogNode<'a, K,V>>>>,
    pub before:Option<std::sync::Weak<RefCell<LogNode<'a, K,V>>>>
}
struct LinkIterator<'a,K,V>{
    current:Option<Arc<RefCell<LogNode<'a, K,V>>>>,
    source:Option<Arc<RefCell<LogNode<'a, K,V>>>>
}
impl <'a, K, V> LinkIterator<'a, K, V> {
    pub fn new(source:Option<Arc<RefCell<LogNode<'a, K,V>>>>) -> Self {
        LinkIterator {
           current: None,
           source
        }
    }
}
impl <'a, K,V> Iterator for LinkIterator<'a, K,V>{
    type Item=Arc<RefCell<LogNode<'a, K,V>>>;
    fn next(&mut self) -> Option<Self::Item> {
        if self.current.is_none() && self.source.is_some(){
            self.current=self.source.clone();
        }else{
            if std::ptr::eq(self.source.as_ref().unwrap().as_ptr(),self.current.as_ref().unwrap().as_ptr()) {
                return None;
            }
        } 
        let current=&self.current.as_ref().unwrap().clone();
        self.current=current.borrow().next.clone();
        Some(current.clone())
    }
}

#[allow(dead_code)]
struct LinkedMapList<'a, K,V>{
    size:u16,
    capacity:u16,
    head:Option<Arc<RefCell<LogNode<'a, K,V>>>>,
    _private: ()
}

unsafe impl <'a, K,T> Send for LinkedMapList<'a, K,T> {}
unsafe impl <'a, K,T> Sync for LinkedMapList<'a, K,T> {}


impl<'a,K,V> LinkedMapList<'a, K,V>{
    fn new(capacity:u16)->Self{
        LinkedMapList{
            size: 0,
            capacity: capacity,
            head: None,
            _private:(),
        }
    }
    fn push(&mut self,key:K,up:V,down:V){  
        if &self.size < &self.capacity { 
            let current: Arc<RefCell<LogNode<'_, K, V>>>=Arc::new(RefCell::new(LogNode{ key, up,down,next:None, before:None}));
            let sp=Some(Arc::clone(&current));
            let wp=Some(Arc::downgrade(&current));
            if self.head.is_none(){
                self.head=Some(Arc::clone(&current));
                current.borrow_mut().next=sp;
                current.borrow_mut().before=wp;
            }else{
               let head_node=self.head.clone().unwrap();
               let tail_node=head_node.borrow_mut().before.clone().unwrap().upgrade().unwrap();
               current.borrow_mut().next=tail_node.borrow_mut().next.clone();
               current.borrow_mut().before=head_node.borrow_mut().before.clone();
               tail_node.borrow_mut().next=sp;
               head_node.borrow_mut().before=wp;
            }
            self.size+=1;
        }else{
            let head_node: Arc<RefCell<LogNode<'_, K, V>>>=self.head.clone().unwrap();
            //直接修改该节点的值
            head_node.borrow_mut().key=key;
            head_node.borrow_mut().up=up;
            head_node.borrow_mut().down=down;
            //头节点标记后移 
            self.head=head_node.borrow_mut().next.clone();
        }
    }
    fn iterator(&self)->Option<LinkIterator<'a,K,V>>{
        return Some(LinkIterator::new(self.head.clone()));
    }
}
#[allow(dead_code)]
pub struct TrafficContext<'a>{
    log_context:Option<LinkedMapList<'a, String,String>>
}
impl<'a> TrafficContext<'a>{
    pub fn push_log(&mut self,time:String,up:String,down:String){
        if self.log_context.is_none() {
            self.log_context=Some(LinkedMapList::new(600 as u16));
        }
        self.log_context.as_mut().unwrap().push(time, up, down);
        // self.log_context.and_then(|context|Some(context.push(time, up, down)));
    }
}
impl <'a> std::fmt::Display for TrafficContext<'a>{
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result{
        write!(f, "[")?;
        let list: &LinkedMapList<'_, String, String>=self.log_context.as_ref().unwrap();
        let mut iterator=list.iterator().unwrap();
        loop{
            let current=iterator.next().clone();
            if current.is_some() {
                let cc=current.unwrap();
                write!(f,"( time: {}, up {}, down {} )",cc.borrow().key,cc.borrow().up,cc.borrow().down)?;        
            }else{
                break;
            }
        }
        write!(f, "]")
    }
}


struct TrafficContextMap<'a>{
    traffic_map:HashMap<String,TrafficContext<'a>>
} 

struct Server<'a>{
    server_status: Arc<std::sync::atomic::AtomicBool>,
    traffic_context_map:Arc<Mutex<RefCell<TrafficContextMap<'a>>>>,
}
impl Server<'_> {
    fn start(&mut self) -> Result<bool, String> {
        let local_status = Arc::clone(&self.server_status);
        let _thread = std::thread::spawn(move || {
            println!("count thread startting...");
            'outer: loop {
                for _ in 0..10 {
                    if local_status.load(std::sync::atomic::Ordering::Relaxed) {
                        break 'outer;
                    }
                }
                let locker=self.traffic_context_map.as_ref().clone();
                let mut data=locker.lock().unwrap().get_mut();
                let history_data=data.traffic_map.get("00001").as_mut().unwrap();
                history_data.push_log(Local::now().format("%Y-%m-%d %H:%M:%S").to_string(), "123".to_owned(),"456".to_owned());
            }
        });
        log::info!("adapter up success");
        Ok(self.server_status.load(std::sync::atomic::Ordering::Relaxed))
    }
}
#[test]
fn test_server() {

}
#[test]
fn test_tcontext() {
    let mut tcontext: TrafficContext<'_>=TrafficContext{ log_context: None};
    tcontext.push_log("2021-08-09".to_owned(), "23".to_owned(), "34".to_owned());
    tcontext.push_log("2021-08-10".to_owned(), "22".to_owned(), "39".to_owned());
    tcontext.push_log("2021-08-11".to_owned(), "2".to_owned(), "3".to_owned());
    tcontext.push_log("2021-08-12".to_owned(), "93".to_owned(), "84".to_owned());
    tcontext.push_log("2021-08-13".to_owned(), "0".to_owned(), "0".to_owned());
    print!("info >> {}",tcontext);
}

评论区

写评论
作者 recently-lxh 2023-09-04 10:50

使用scopedthread,确实可以了

--
👇
yuyidegit: TrafficContextMap<'a>这个带非'static生命周期的东西不能放到其他线程执行,除非你用scopedthread

yuyidegit 2023-09-01 21:08

TrafficContextMap<'a>这个带非'static生命周期的东西不能放到其他线程执行,除非你用scopedthread

1 共 2 条评论, 1 页