0

A thread should read content from stdout or stderr in pass the read content to via a channel. Now want to create one Thread for stdout and one for stderr, because I they have the same behaviour I dont want to pass the ChildStdout and ChildStderr structs rather than the a generic that implements the Read trait.

This is my method:

fn start_read_thread<T : Read + Send>(stdout: Option<T>, process: &mut Child) -> Result<Receiver<Result<Vec<u8>, ()>>, ()> {
    let (tx_stdout, rx_stdout): (Sender<Result<Vec<u8>, ()>>, Receiver<Result<Vec<u8>, ()>>) = mpsc::channel();
    std::thread::spawn(move || {
        for b in stdout.unwrap().bytes() {
            let b = b.unwrap();
        }
    });
    return Ok(rx_stdout);
}

Now the compiler says:

    the parameter type `T` may not live long enough
   --> shell_execution\src\powershell.rs:146:17
    |
142 |     fn start_read_thread<'a, T : Read + Send>(stdout: Option<T>, process: &mut Child) -> Result<Receiver<Result<Vec<u8>, ()>>...
    |                              -- help: consider adding an explicit lifetime bound...: `T: 'static +`
...
146 |                 std::thread::spawn(move || {
    |                 ^^^^^^^^^^^^^^^^^^ ...so that the type `[closure@shell.rs:146:36: 148:18]` will meet its required lifetime bounds

Should T not always live long enough, because it gets moved to the thread scope it can't be dropped somewhere else?

Replacing T with ChildStdout works, without the need of adding the static lifetime.

Does someone know why this is happening, and do I build a memory leak with this static lifetime?

Thanks

playground

Ace of Spade
  • 388
  • 3
  • 22
  • `'static` bound on `T` means that `T` itself does not contain any references to non-`'static` data. In your case, `stdout` is moved to the closure, but there is no guarantee that `T` won't contain references to something that has a shorter lifetime. – justinas Mar 23 '21 at 14:51
  • Also see [How can I pass a reference to a stack variable to a thread?](https://stackoverflow.com/questions/32750829/how-can-i-pass-a-reference-to-a-stack-variable-to-a-thread) for rationale. – trent Mar 23 '21 at 15:00
  • Re: *do I build a memory leak with this static lifetime?* No; lifetimes don't actually *do* anything, so using `'static` instead of some shorter lifetime will never leak memory or make some value live longer. But actually, `thread::spawn` is one of the ways you can leak memory: if you send something to another thread, and the other thread never drops it or terminates, the value is leaked. So... yes? Maybe? – trent Mar 23 '21 at 15:05
  • @justinas but why can I pass values that are created in another method. So they do not have a static lifetime? – Ace of Spade Mar 23 '21 at 15:32
  • 2
    @AceofSpade It's important to realize that `T: 'static` **doesn't** mean that the data `T` is static (valid for the whole progam)! It just means that `T` may only contain owned data that can last as long as `T` (e.g. `String`, `Vec` embedded in `T`) and **if** it happens to contain any _references_, those references must point to static data (such as string literals or global vars). See [this article](https://github.com/pretzelhammer/rust-blog/blob/master/posts/common-rust-lifetime-misconceptions.md#2-if-t-static-then-t-must-be-valid-for-the-entire-program) for a more detailed explanation. – user4815162342 Mar 23 '21 at 15:39
  • @user4815162342 thanks for this article. Do I understand correctly that I have to do a 'drop(stdout)' in my thread, because otherwise that would leak memory? – Ace of Spade Mar 24 '21 at 09:54
  • @AceofSpade I'm honestly confused by your question, but I believe the answer is "no". Rust is very strict with ownerships and, unless you intentionally call `std::mem::forget()`, you are very unlikely to randomly leak memory. As was already explained in a previous comment, the lifetimes can't cause leaks, all they do is prevent dangling references from occurring by refusing to compile the code that might cause them. – user4815162342 Mar 24 '21 at 12:12

0 Answers0