如何在线程中使用静态生命周期?

Posted

技术标签:

【中文标题】如何在线程中使用静态生命周期?【英文标题】:How do I use static lifetimes with threads? 【发布时间】:2015-08-14 06:14:27 【问题描述】:

我目前正在努力解决 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 的一次迭代中),但我不知道这样做的正确方法是什么。

我是否应该按照编译器的提示尝试将&amp;str 转换为&amp;'static str? 如果每一行都有'static 生命周期,我是否会泄漏内存? 我什么时候应该使用'static?这是我应该尽量避免的事情还是完全可以? 有没有更好的方法通过通道在结构中传递Strings?

对于那些幼稚的问题,我深表歉意。我已经花了很长时间搜索,但我无法完全理解它。这可能是我的动态语言背景妨碍了:)

顺便说一句:&amp;input[..]String 转换为&amp;str 是否被认为可以?这是我能找到的唯一稳定的方法。

【问题讨论】:

【参考方案1】:

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

在您的情况下,可能会出现问题的是,如果主循环发送对线程的引用并在该字符串被线程处理之前销毁该字符串。线程在处理字符串时会访问无效内存。

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

struct Message 
    text: String,

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

现在您正在将所有权(移动)从主线程转移到处理程序线程。因为您移动了您的值,所以不涉及任何引用,也不再适用终身检查。

【讨论】:

【参考方案2】:

您无法将&amp;'a T 转换为&amp;'static T,除非内存泄漏。幸运的是,这根本没有必要。没有理由向线程发送借来的指针并将行保留在主线程上。您不需要主线程上的行。只需发送线路本身,即发送String

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

在线程之间发送非'static 引用是不安全的,因为你永远不知道另一个线程会继续使用它多久,所以你不知道借用何时到期并且对象可以被释放。请注意,作用域线程不存在此问题(不在 1.0 中,但我们所说的正在重新设计)确实允许这样做,但常规的 spawned 线程可以。

'static 不是您应该避免的事情,它的作用非常好:表示一个值在程序运行的整个持续时间内都存在。但如果这不是你想要表达的意思,那当然是错误的工具。

【讨论】:

哦,好的。这是一个简单的解决方案。在struct 中用String 替换&amp;str 就可以了。谢谢,我真的应该先尝试一下。

以上是关于如何在线程中使用静态生命周期?的主要内容,如果未能解决你的问题,请参考以下文章

Java线程的生命周期

java 静态变量生命周期(类生命周期)(转)

c++类中 各种成员的生命周期?

高并发线程的生命周期其实没有我们想象的那么简单!!

Java并发基础Java线程的生命周期

java基础——线程的常用方法和线程生命周期