Rust从关联函数启动线程

nle07wnf  于 2023-10-20  发布在  其他
关注(0)|答案(3)|浏览(182)

我试图写一个运行相关的方法,将启动一个新的线程,并保持运行。线程句柄保存在结构属性中,但我得到以下错误:

error[E0521]: borrowed data escapes outside of method                                                                                                                                                                                                                                                              
  --> src\server\dispatcher.rs:33:27
   |
28 |       pub fn run(&mut self) {
   |                  ---------
   |                  |
   |                  `self` is a reference that is only valid in the method body
   |                  let's call the lifetime of this reference `'1`
...
33 |           let main_thread = thread::spawn(move || loop {
   |  ___________________________^
34 | |             match rx.try_recv() {
35 | |                 Ok(_) | Err(TryRecvError::Disconnected) => {
36 | |                     break;
...  |
43 | |             }
44 | |         });
   | |          ^
   | |          |
   | |__________`self` escapes the method body here
   |            argument requires that `'1` must outlive `'static`
   |

我的代码:

pub fn run(&mut self) {
    let (tx, rx) = mpsc::channel::<()>();

    let packets = Arc::new(Mutex::new((&self.packets)));

    let main_thread = thread::spawn(move || loop {
        match rx.try_recv() {
            Ok(_) | Err(TryRecvError::Disconnected) => {
                break;
            }
            Err(TryRecvError::Empty) => {
                let inside = packets.clone();

                let qwe = packets.lock().unwrap();
            }
        }
    });

    self.main_thread = Some(main_thread);
}
nvbavucw

nvbavucw1#

解决方案可能会以某种方式使用thread::scope()
您正在生成一个捕获packets的线程,其中包含self的引用(指针)。对于编译器来说,当程序结束时,线程可能仍然在运行,在self被释放很长时间后访问它。
如果你从作用域中派生线程,编译器知道当作用域结束时它将被连接(等待)。您也可以在示波器末端发送停止信号。
有多种选择如何继续。您可以在外部创建范围并将其传递给run()。或者,您可以向run()传递一个额外的lambda,其中包含创建线程后要执行的代码,因此您不必将任何特定于线程的内容存储到self中。或者你不能在线程内部使用任何引用,并让它拥有通过队列的任何内容。

k4emjkb1

k4emjkb12#

这与相关功能无关。
packets捕获对self.packets的引用。然后将其移动到线程中。但是你不能将引用移到线程中,除非它们引用静态数据,因为线程可能比它引用的任何东西都活得长。

czq61nw1

czq61nw13#

问题是你在一个新线程中借用了self.packets。借用检查器不知道这个线程将存活多久,但是self的借用只对当前函数调用有效。
您没有提供完整的代码示例,但简化一点,也许这是代表性的:

use std::sync::{mpsc, Arc, Mutex, mpsc::*};
use std::thread;

struct Foo {
    packets: Vec<i32>
}

impl Foo {
    pub fn run(&mut self) -> (thread::JoinHandle<()>, mpsc::Sender<()>) {
        let (tx, rx) = mpsc::channel::<()>();
        let packets = Arc::new(Mutex::new(&self.packets));
        let handle = thread::spawn(move || loop {
            match rx.try_recv() {
                Ok(_) | Err(TryRecvError::Disconnected) => {
                    break;
                }
                Err(TryRecvError::Empty) => {
                    let qwe = packets.lock().unwrap();
                }
            }
        });
        (handle, tx)
    }
}

通过在struct字段上将共享数据设置为Arc,没有借用-只有Arc的克隆:

use std::sync::{mpsc, Arc, Mutex, mpsc::*};
use std::thread;

struct Foo {
    packets: Arc<Mutex<Vec<i32>>>
}

impl Foo {
    pub fn run(&mut self) -> (thread::JoinHandle<()>, mpsc::Sender<()>) {
        let (tx, rx) = mpsc::channel::<()>();
        let packets = self.packets.clone();
        let handle = thread::spawn(move || loop {
            match rx.try_recv() {
                Ok(_) | Err(TryRecvError::Disconnected) => {
                    break;
                }
                Err(TryRecvError::Empty) => {
                    let qwe = packets.lock().unwrap();
                }
            }
        });
        (handle, tx)
    }
}

这是因为线程没有从self借用任何东西。

相关问题