[Solved] "Reference must be valid for the static lifetime..." Why?


#1

My scan() function gets an input_slice, then spans 4 worker-threads and sends the output to the channel tx.

The merger() thread collects the output from the channel tx for printing.

From my understanding no thread can outlive the scan() function. So the input_slice can be given back securely after borrowing.

Why does the borrow checker wants mmap to be static? What can I do?

extern crate memmap;
use std::sync::mpsc;
use std::sync::mpsc::SyncSender;

use std::fs::File;
use memmap::{Mmap, Protection};
use std::str;

extern crate scoped_threadpool;
use scoped_threadpool::Pool;
use std::thread;

const MESSAGE_BUF: usize = 20;


fn scan<'a> (mission: &Vec<&'a str>, input_slice: &'a  [u8], pool: &mut Pool, 
                tx: &SyncSender<&'a str>)  {
           pool.scoped(|scope| {
            for e in mission.iter().enumerate() {
                let tx = tx.clone();
                scope.execute(move || {
                    let m = std::str::from_utf8(input_slice).unwrap().clone();
                    //let m =  e.1;
                    println!("{}",m);
                    
                    tx.send(m).unwrap();
                });
            }
        });
  

} 


fn main() {
    let f = File::open("./scanme.txt").unwrap();
    let mmap = Mmap::open(&f, Protection::Read).unwrap();
    let mission = vec!["T0", "T1", "T2", "T3"];
    let n_threads = mission.len();
    let (tx, rx) = mpsc::sync_channel(MESSAGE_BUF);

    let merger = thread::spawn(move || {
        for i in 0..n_threads*4 {
            println!("\tListening...");
            println!("\t\tGot: {:?}", rx.recv().expect("Err"));
        }
    });

    let mut pool = Pool::new(n_threads as u32); 

    for i in 0..4 {
        let input = unsafe {&mmap.as_slice()[i..10*i]};   //error: `mmap` does not live long enough
        scan(&mission, &input, &mut pool, &tx); 
    }


    merger.join().unwrap();
    println!("All threads terminated.");
}
main.rs:62:30: 62:34 error: `mmap` does not live long enough
main.rs:62         let input = unsafe {&mmap.as_slice()[i..10*i]};
                                        ^~~~
main.rs:62:30: 62:34 note: reference must be valid for the static lifetime...
main.rs:44:58: 70:2 note: ...but borrowed value is only valid for the block suffix following statement 2 at 44:57
main.rs:44     let mmap = Mmap::open(&f, Protection::Read).unwrap();

#2

While I’m not 100% sure about all the details going on here, my best guess is that this hinges on the fact that your scan<'a> function takes a tx: &SyncSender<&'a str> parameter.
This means that you are sending a reference through the channel to be read at a later (and to the compiler unspecified) point in time, so the 'a here has to be 'static. (How the type system rules come to this result in this specific case is something i’m a little unclear about.)
You could try sending a String instead of a &str through the channel.
Or you could try to put the merger thread into a scoped_threadpool as well, but since I’m unclear about the exact type system interactions here, I don’t know if that really solves anything.


#3

Thank you! It was indeed the &str message sent out. I changed it to String and it compiles.
I was only focused on mmap and did not see it.

Here the working code:

extern crate memmap;
use std::sync::mpsc;
use std::sync::mpsc::SyncSender;

use std::fs::File;
use memmap::{Mmap, Protection};
use std::str;

extern crate scoped_threadpool;
use scoped_threadpool::Pool;
use std::thread;
use std::thread::sleep;
use std::time::Duration;


const MESSAGE_BUF: usize = 20;


fn scan<'a> (mission: &Vec<&'a str>, input_slice: &'a  [u8], pool: &mut Pool, 
                tx: &SyncSender<String>)  {
           pool.scoped(|scope| {
            for e in mission.iter().enumerate() {
                let tx = tx.clone();
                scope.execute(move || {
                    if e.0 == 3 {
                        sleep(Duration::from_secs(1));
                    }
                    let m = std::str::from_utf8(input_slice).unwrap().to_string();
                    //let m =  e.1;
                    println!("{}",m);
                    
                    tx.send(m).unwrap();
                });
            }
        });
  

} 


fn main() {
    let f = File::open("./scanme.txt").unwrap();
    let l = f.metadata().unwrap().len() as usize;
    let mmap = Mmap::open(&f, Protection::Read).unwrap();
    let mission = vec!["T0", "T1", "T2", "T3"];
    let n_threads = mission.len();
    let (tx, rx) = mpsc::sync_channel(MESSAGE_BUF);

    let merger = thread::spawn(move || {
        for i in 0..n_threads*4 {
                if i == 6 {
                    sleep(Duration::from_secs(7));
                }
            println!("\tListening...");
            println!("\t\tGot: {:?}", rx.recv().expect("Err"));
        }
    });

    let mut pool = Pool::new(n_threads as u32); // no threads

    for i in 0..4 {
        let input = unsafe {&mmap.as_slice()[10*i..10*(i+1)]};
        scan(&mission, &input, &mut pool, &tx); 
    }


    merger.join().unwrap();
    println!("All threads terminated.");

}