In C++ we have std::promise and std::future, which will sometimes help in getting the result or status of a task executed by a thread in another thread, for example main thread.
How can the same be achieved in Rust? Basically I'm looking for a (non-async/tokio) Rust equivalent of the below C++ code.
#include <chrono>
#include <future>
#include <iostream>
#include <thread>
void foo(std::promise<int>&& p) {
auto p1 = std::move(p);
using namespace std::chrono_literals;
std::this_thread::sleep_for(5000ms);
p1.set_value(42);
}
int main() {
std::promise<int> p;
std::future<int> f = p.get_future();
std::jthread jt1(foo, std::move(p));
std::cout << "waiting" << std::endl;
std::cout << f.get() << std::endl;
jt1.join();
}
Sync rust does not have futures (and the future trait doesn't really have the properties you're seeking).
There are a few options though neither is an exact match for a future
Rust threads can return values, so having a side-channel is not necessary if your thread is a one-shot worker, JoinHandle::join does the job:
fn main() {
let t = std::thread::spawn(foo);
println!("{:?}", t.join());
}
fn foo() -> i32 {
std::thread::sleep(std::time::Duration::from_millis(500));
42
}
Oneshot is ideal but the stdlib doesn't have one, mpsc is a bit worse because it can't be consumed (and could have multiple producers) but probably good enough in most situations
use std::sync::mpsc::{sync_channel, SyncSender};
fn main() {
let (s, r) = sync_channel(0);
let t = std::thread::spawn(move || foo(s));
println!("{:?}", r.recv());
t.join().unwrap();
}
fn foo(c: SyncSender<i32>) {
std::thread::sleep(std::time::Duration::from_millis(500));
c.send(42).unwrap();
}
OnceLockThis is a pretty recent addition to the stdlib, and has the drawback of being symmetrical (rather than having a reader and a writer side), but you can easily wrap it into a sender and a receiver if you want to force more promise-style properties
use std::sync::{Arc, OnceLock};
fn main() {
let l = Arc::new(OnceLock::new());
let t = std::thread::spawn({
let l = l.clone();
move || foo(l)
});
println!("{:?}", l.wait());
t.join().unwrap();
}
fn foo(l: Arc<OnceLock<i32>>) {
std::thread::sleep(std::time::Duration::from_millis(500));
l.set(42).unwrap();
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With