无法在线程之间发送& str,因为它的活动时间不够长

时间:2016-08-14 09:40:21

标签: thread-safety closures rust threadpool channel

鉴于以下简化程序:

#[macro_use] extern crate log;
extern crate ansi_term;
extern crate fern;
extern crate time;
extern crate threadpool;
extern crate id3;

mod logging;

use std::process::{exit, };
use ansi_term::Colour::{Yellow, Green};
use threadpool::ThreadPool;
use std::sync::mpsc::channel;
use std::path::{Path};
use id3::Tag;

fn main() {
    logging::setup_logging();

    let n_jobs = 2;

    let files = vec!(
        "/tmp/The Dynamics - Version Excursions/01-13- Move on Up.mp3",
        "/tmp/The Dynamics - Version Excursions/01-09- Whole Lotta Love.mp3",
        "/tmp/The Dynamics - Version Excursions/01-10- Feel Like Making Love.mp3"
    );
    let pool = ThreadPool::new(n_jobs);
    let (tx, rx) = channel();
    let mut counter = 0;

    for file_ in files {
        let file_ = Path::new(file_);
        counter = counter + 1;
        let tx = tx.clone();

        pool.execute(move || {
            debug!("sending {} from thread", Yellow.paint(counter.to_string()));

            let tag = Tag::read_from_path(file_).unwrap();
            let a_name = tag.artist().unwrap();

            debug!("recursed file from: {} {}",
                   Green.paint(a_name), file_.display());

            tx.send(".").unwrap();
            // TODO amb: not working..
            // tx.send(a_name).unwrap();
        });
    }

    for value in rx.iter().take(counter) {
        debug!("receiving {} from thread", Green.paint(value));
    }
    exit(0);
}

一切都按预期工作,除非一条注释行(tx.send(a_name).unwrap();)被放回去。在这种情况下,我收到以下错误:

error: `tag` does not live long enough
            let a_name = tag.artist().unwrap();
                         ^~~
    note: reference must be valid for the static lifetime...
note: ...but borrowed value is only valid for the block suffix following statement 1 at 39:58
            let tag = Tag::read_from_path(file_).unwrap();
            let a_name = tag.artist().unwrap();

            debug!("recursed file from: {} {}",
                   Green.paint(a_name), file_.display());

...

通常我理解编译器告诉我的内容,但我没有看到问题,因为变量tag是在闭包块内定义的。我能猜到的唯一问题是变量txclone之外,因此可能会与tag的生命周期发生冲突。

我的目标是将所有当前逻辑放在线程内部的线程闭包中,因为这是我想要传播到多个线程的“处理”。我怎样才能实现这一目标,但仍然会向现有的tx更长的时间发送一些价值?

我正在使用以下Rust版本:

$ rustc --version
rustc 1.9.0 (e4e8b6668 2016-05-18)
$ cargo --version
cargo 0.10.0-nightly (10ddd7d 2016-04-08)

1 个答案:

答案 0 :(得分:3)

a_name &str来自tag。因此,它的生命周期由tag限定。将非'static引用沿着通道发送到另一个线程是不安全的。它指的是线程堆栈上的东西,一旦接收器试图访问它就可能不再存在。 在您的情况下,您应该将a_name提升为类型String的拥有值,该值将移至接收方线程。

tx.send(a_name.to_owned()).unwrap();