如何使用线程的静态生命周期



我目前正在努力解决Rust(1.0)的生命周期问题,特别是在通过通道传递结构体时。

我如何得到这个简单的例子编译:

use std::sync::mpsc::{Receiver, Sender};
use std::sync::mpsc;
use std::thread::spawn;
use std::io;
use std::io::prelude::*;
struct Message<'a> {
    text: &'a str,
}
fn main() {
    let (tx, rx): (Sender<Message>, Receiver<Message>) = mpsc::channel();
    let _handle_receive = spawn(move || {
        for message in rx.iter() {
            println!("{}", message.text);
        }
    });
    let stdin = io::stdin();
    for line in stdin.lock().lines() {
        let message = Message {
            text: &line.unwrap()[..],
        };
        tx.send(message).unwrap();
    }
}

:

error[E0597]: borrowed value does not live long enough
  --> src/main.rs:23:20
   |
23 |             text: &line.unwrap()[..],
   |                    ^^^^^^^^^^^^^ does not live long enough
...
26 |     }
   |     - temporary value only lives until here
   |
   = note: borrowed value must be valid for the static lifetime...

我可以看到为什么会这样(line只适用于for的一次迭代),但我不知道这样做的正确方法是什么。

  • 我应该,作为编译器提示,试图将&str转换成&'static str ?
  • 如果每一行都有'static生命周期,我是否会泄漏内存?
  • 我什么时候应该使用'static呢?这是我应该尽量避免的还是完全可以的?
  • 是否有更好的方法通过通道在结构体中传递 Strings ?
我为那些幼稚的问题道歉。我已经花了相当多的时间搜索了,但我还是不能完全理解它。这可能是我的动态语言背景妨碍了我:)

作为题外话:&input[..]是否用于将String转换为&str ?这是我能找到的唯一稳定的方法。

您不能将&'a T转换为&'static T,除非通过泄漏内存。幸运的是,这根本没有必要。没有理由将借来的指针发送给线程并将这些行保留在主线程中。你不需要主线程中的代码行。只发送行本身,即发送String

如果需要从多个线程访问(并且您不想克隆),请使用Arc<String>(将来,Arc<str>也可以)。这样,字符串在线程之间共享,正确地共享,因此当没有线程不再使用它时,它将被释放。

在线程之间发送非'static引用是不安全的,因为你永远不知道其他线程将继续使用它多长时间,所以你不知道什么时候借用到期,对象可以被释放。请注意,作用域的线程不会有这个问题(1.0中没有,但我们正在重新设计),但常规的spawn线程会。

'static不是你应该避免的东西,它的作用是完美的:表示一个值在程序运行的整个过程中都存在。但如果这不是你想要传达的,那当然是错误的工具。

这样想:线程没有语法生命周期,即线程不会在创建它的代码块结束时被丢弃。无论向线程发送什么数据,都必须确保它和线程一样长,也就是永远。这意味着'static

在你的例子中,如果主循环向线程发送引用并在线程处理字符串之前销毁该字符串,则可能出现问题。处理字符串时,线程将访问无效内存。

一种选择是将行放入静态分配的容器中,但这意味着您永远无法销毁这些字符串。一般来说,这是个坏主意。另一种选择是考虑:主线程在读取该行之后是否真的需要该行?如果主线程将line的责任转移到处理线程会怎样?

struct Message {
    text: String,
}
for line in stdin.lock().lines() {
    let message = Message {
        text: line.unwrap(),
    };
    tx.send(message).unwrap();
}

现在你正在将所有权(移动)从主线程转移到处理线程。因为您移动了值,所以不涉及引用,也不再应用生命周期检查。

相关内容

  • 没有找到相关文章

最新更新