如果您的代码中没有带有生存期的变量,请使用某种类型的共享所有权,例如 Arc 与可以确保只有一个线程可以对该变量进行突变的内容配对,例如 Mutex 就足够了.这允许每个线程拥有共享值,并在最后一个线程退出时最终将其删除.有关详细信息,请参见如何在线程之间共享可变对象?.I've got a thread that launches worker threads, all are expected to live forever. Each worker thread maintains it's own list of Sockets.Some operations require that I traverse all sockets currently alive, but I'm having trouble with lifetimes trying to create a master list of sockets containing a pointer to a socket owned by another list.use std::{str, thread};use std::thread::JoinHandle;use std::io::{Read, Write};use std::net::{TcpListener, TcpStream};use std::sync::{Arc, Mutex};use std::ops::DerefMut;use std::sync::mpsc::{channel, Sender, Receiver, TryRecvError};use self::socketlist::SocketList;use self::mastersocketlist::MasterSocketList;pub struct Socket { user: String, stream: TcpStream,}mod socketlist { use self::SocketList::{Node, End}; use super::Socket; pub enum SocketList { Node(Socket, Box<SocketList>), End, } impl SocketList { pub fn new() -> SocketList { End } pub fn add(self, socket: Socket) -> SocketList { Node(socket, Box::new(self)) } pub fn newest<'a>(&'a mut self) -> Result<&'a Socket, String> { match *self { Node(ref mut socket, ref mut next) => Ok(socket), End => Err("No socket available".to_string()), } } }}mod mastersocketlist { use self::MasterSocketList::{Node, End}; use super::Socket; pub enum MasterSocketList<'a> { Node(Box<&'a Socket>, Box<MasterSocketList<'a>>), End, } impl<'a> MasterSocketList<'a> { pub fn new() -> MasterSocketList<'a> { End } pub fn add(self, socket: &'a Socket) -> MasterSocketList<'a> { MasterSocketList::Node(Box::new(&socket), Box::new(self)) } }}pub struct SlotManager { prox: JoinHandle<()>, prox_tx: Sender<TcpStream>,}impl SlotManager { pub fn new() -> SlotManager { let (tx, rx): (Sender<TcpStream>, Receiver<TcpStream>) = channel(); let tx_clone = tx.clone(); let prox = thread::spawn(move || SlotManager::event_loop(tx, rx)); SlotManager { prox: prox, prox_tx: tx_clone, } } pub fn sender(&self) -> Sender<TcpStream> { self.prox_tx.clone() } fn event_loop(tx: Sender<TcpStream>, rx: Receiver<TcpStream>) { let socket_list = Arc::new(Mutex::new(MasterSocketList::new())); let mut slot = Slot::new(socket_list.clone()); loop { match rx.try_recv() { Ok(stream) => slot.new_connection(stream), Err(e) => {} } } }}pub struct Slot { prox: JoinHandle<()>, prox_tx: Sender<TcpStream>,}impl Slot { pub fn new(master_socket_list: Arc<Mutex<MasterSocketList>>) -> Slot { let (tx, rx): (Sender<TcpStream>, Receiver<TcpStream>) = channel(); let tx_clone = tx.clone(); let prox = thread::spawn(move || Slot::event_loop(tx, rx, master_socket_list)); Slot { prox: prox, prox_tx: tx_clone, } } pub fn new_connection(&self, stream: TcpStream) { self.prox_tx.send(stream); } fn event_loop(tx: Sender<TcpStream>, rx: Receiver<TcpStream>, master_socket_list: Arc<Mutex<MasterSocketList>>) { let mut sockets = SocketList::new(); loop { // Check for new connections match rx.try_recv() { Ok(stream) => { let mut socket = Socket { user: "default".to_string(), stream: stream, }; sockets = sockets.add(socket); let mut msl_guard = match master_socket_list.lock() { Ok(guard) => guard, Err(poisoned) => poisoned.into_inner(), }; let mut msl_handle = msl_guard.deref_mut(); *msl_handle = msl_handle.add(sockets.newest().unwrap()); } Err(e) => {} } } }}fn main() { let mut slot_manager = SlotManager::new(); let listener = TcpListener::bind("127.0.0.1:1234").unwrap(); for stream in listener.incoming() { match stream { Ok(stream) => { let sender = slot_manager.sender(); thread::spawn(move || { sender.send(stream); //process_new_connection(stream, sender) }); } Err(e) => println!("Connection error: {}", e), } } drop(listener);}The errors that I receive...error[E0477]: the type `[closure@src/main.rs:107:34: 107:86 tx:std::sync::mpsc::Sender<std::net::TcpStream>, rx:std::sync::mpsc::Receiver<std::net::TcpStream>, master_socket_list:std::sync::Arc<std::sync::Mutex<mastersocketlist::MasterSocketList<'_>>>]` does not fulfill the required lifetime --> src/main.rs:107:20 |107 | let prox = thread::spawn(move || Slot::event_loop(tx, rx, master_socket_list)); | ^^^^^^^^^^^^^ | = note: type must outlive the static lifetimeI don't even know if what I am trying to is possible as safe code.I wanting the mastersocketlist to contain a pointer to a socket where the socket's lifetime is defined by the thread that created it. I believe that's what all those errors mean, but I have no idea how to provide the proper lifetime annotations to fix it. 解决方案 A great thing about Rust is that the type-checking across functions is done solely by the function signature. That means you can replace most of the bodies of functions with unimplemented!() and preserve type-checking errors.Repeat that process a few times, and you end up not calling a lot of functions - remove those. Inlining modules and reducing structs / enums can also help.At some point your error will disappear - the first clue towards the problem! Keep at it, and you get a tiny reproduction:use std::sync::{Arc, Mutex};use std::thread;pub enum MasterSocketList<'a> { One(&'a u8),}pub struct Slot;impl Slot { pub fn new<'a>(master_socket_list: Arc<Mutex<MasterSocketList<'a>>>) -> Slot { thread::spawn(move || { master_socket_list; }); unimplemented!(); }}fn main() {}Checking out the error, it still matches:error[E0477]: the type `[closure@src/main.rs:12:23: 14:10 master_socket_list:std::sync::Arc<std::sync::Mutex<MasterSocketList<'a>>>]` does not fulfill the required lifetime --> src/main.rs:12:9 |12 | thread::spawn(move || { | ^^^^^^^^^^^^^ | = note: type must satisfy the static lifetimeLet's check the docs for the signature of thread::spawn:pub fn spawn<F, T>(f: F) -> JoinHandle<T>where F: FnOnce() -> T, F: Send + 'static, T: Send + 'static,The key point here is F: Send + 'static - the closure you give to spawn must only contain references that last the entire life of the program. This is because spawn can create threads that become detached. Once detached, the thread could live forever, so all references must live at least that long, otherwise you'd get dangling references, a bad thing! Rust saves the day, once again!If you want to guarantee that the threads will terminate at a known point, you can use scoped threads, such as those provided by scoped-threadpool or crossbeam.If your code didn't have a variable with a lifetime inside of it, using some type of shared ownership like Arc paired with something that will ensure only one thread can mutate the variable, like Mutex would have been sufficient. This allows each thread to own the shared value, finally dropping it whenever the last thread exits. See How do I share a mutable object between threads? for details. 这篇关于线程之间共享引用时会遇到麻烦的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持! 上岸,阿里云!
05-27 04:57
查看更多