Reputation: 2945
A rust newbie here.
I would like to launch an external long-running process and talk with it over pipes from multiple threads in Rust.
I am getting lifetime errors and can't figure the proper way to please the lifetimes checker. What are the ways to restructure this?
Consider the following example:
use std::process::{Command, Stdio, ChildStdin};
use std::sync::Mutex;
use std::io::{Write};
use std::thread;
struct Element {
sink: Mutex<Option<ChildStdin>>
}
impl Element {
fn launch_process(&self) {
let child =
Command::new("sed").args(&["s/foo/bar/g"])
.stdin(Stdio::piped())
.spawn()
.unwrap();
let mut sink = self.sink.lock().unwrap();
*sink = child.stdin;
}
fn tx(&self, content: &[u8]) {
let mut sink = self.sink.lock().unwrap();
sink.as_mut().unwrap().write(content);
}
fn start_tx(&self) {
thread::spawn( || {
self.tx(b"foo fighters");
});
}
}
fn main() {
let e = Element {
sink: Mutex::new(None)
};
e.launch_process();
e.start_tx();
}
If I remove the thread::spawn
bit then everything works as expected. With thread::spawn
in place, I get the error:
error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements
--> src/main.rs:28:24
|
28 | thread::spawn( || {
| ________________________^
29 | | self.tx(b"foo fighters");
30 | | });
| |_________^
|
note: first, the lifetime cannot outlive the anonymous lifetime #1 defined on the method body at 27:5...
--> src/main.rs:27:5
|
27 | / fn start_tx(&self) {
28 | | thread::spawn( || {
29 | | self.tx(b"foo fighters");
30 | | });
31 | | }
| |_____^
= note: ...so that the types are compatible:
expected &&Element
found &&Element
= note: but, the lifetime must be valid for the static lifetime...
note: ...so that the type `[closure@src/main.rs:28:24: 30:10 self:&&Element]` will meet its required lifetime bounds
--> src/main.rs:28:9
|
28 | thread::spawn( || {
| ^^^^^^^^^^^^^
error: aborting due to previous error
Upvotes: 3
Views: 1019
Reputation: 100090
You can't pass &self
(a temporary borrow) to a thread, because the thread may keep running after the reference is no longer valid.
For using data from threads you have only two options:
Give ownership (which is exclusive) of the object to the thread, i.e. use move ||
closure, and don't try to use that object afterwards from the main thread, or any other thread.
Wrap the object in Arc
to get shared thread-safe ownership, and send a clone to the thread (with Arc::clone
it's cheap and the underlying data is shared).
When the compiler says that you need a "static lifetime", ignore that. For all practical purposes, it means "references are not allowed".
Upvotes: 1