Home > OS >  Rust - How to pass function parameters to closure
Rust - How to pass function parameters to closure

Time:11-19

I'm trying to write a function that takes two parameters. The function starts two threads and uses one of the parameters inside one of the thread closures. This doesn't work because of the error "Borrowed data escapes outside of closure". Here's the code.

pub fn measure_stats(testdatapath: &PathBuf, filenameprefix: &String) {
    let (tx, rx) = mpsc::channel();
   
    let filename = format!("test.txt")
    let measure_thread = thread::spawn(move || {
        let stats = sar();
        fs::write(filename, stats).expect("failed to write output to file");

        // Send a signal that we're done.
        let _ = tx.send(());
    });

    thread::spawn(move || {
        let mut n = 0;
        loop {
            // Break if the measure thread is done.
            match rx.try_recv() {
                Ok(_) | Err(TryRecvError::Disconnected) => break,
                Err(TryRecvError::Empty) => {}
            }
            let filename = format!("{:04}.img", n);
            let filepath = Path::new(testdatapath).join(&filename);
            random_file_write(&filepath).unwrap();
            random_file_read(&filepath).unwrap();
            fs::remove_file(&filepath).expect("failed to remove file");
            n  = 1;
        }
    });
    measure_thread.join().expect("joining measure thread panicked");
}

The problem is that testdatapath escapes the function body. I think this is a problem because the lifetime of testdatapath is only guaranteed until the end of the closure, but it needs to be the lifetime of the entire program. But it's a little confusing to me.
I've tried cloning the variable, but that didn't help. I'm not sure how I'm supposed to do this. How do I use a function parameter inside the closure or accomplish the same goal some other more canonical way?

CodePudding user response:

If it's okay for the function not to return until both threads complete, then use std::thread::scope() to create scoped threads instead of std::thread::spawn(). Scoped threads allow borrowing data whereas regular spawning cannot, but require the threads to all terminate before the scope ends and the function that created them returns.

If this has to be a “background” task, then you need to make sure that all the data used by each thread is owned, i.e. not a reference. In this case, that means you should change the parameters to be owned:

pub fn measure_stats(testdatapath: PathBuf, filenameprefix: String) {

Then, those values will be moved into the receiving thread, without any lifetime constraints.

CodePudding user response:

You're trying to make testdata live longer than the function, since this is a value you're borrowing and since you can't guarantee that the original PathBuff will outlive closure running in the new thread the compiler is warning you that you're assuming that this would be the case, but not taking any precautions to do so.

The 3 simpler choices:

  1. Move the PathBuff to the function instead of borrowing it (remove the &).
  2. Use an Arc
  3. clone it and move the clone into the thread.
  • Related