I want to wait for a backend thread (Like this but in my case the backend manages a database which I want to close properly before the application actually exits) to finish (e.g. join it) after application.run() has finished.
My actual non working main.rs (the closure needs to be non-mut)
the thread to wait for
use gio::prelude::*;
use gtk::prelude::*;
use gtk::{ApplicationWindow, Label};
use std::env::args;
use std::thread;
fn main() {
let application = gtk::Application::new(
Some("com.github.gtk-rs.examples.communication_thread"),
Default::default(),
)
.expect("Initialization failed...");
let (thr, mut receiver) = start_communication_thread();
application.connect_activate(move |application| {
build_ui(application, receiver.take().unwrap())
});
application.run(&args().collect::<Vec<_>>());
thr.join();
}
fn build_ui(application: >k::Application, receiver: glib::Receiver<String>) {
let window = ApplicationWindow::new(application);
let label = Label::new(None);
window.add(&label);
spawn_local_handler(label, receiver);
window.show_all();
}
/// Spawn channel receive task on the main event loop.
fn spawn_local_handler(label: gtk::Label, receiver: glib::Receiver<String>) {
receiver.attach(None, move |item| {
label.set_text(&item);
glib::Continue(true)
});
}
/// Spawn separate thread to handle communication.
fn start_communication_thread() -> (thread::JoinHandle<()>, Option<glib::Receiver<String>>) {
let (sender, receiver) = glib::MainContext::channel(glib::PRIORITY_DEFAULT);
let thr = thread::spawn(move || {
let mut counter = 0;
loop {
let data = format!("Counter = {}!", counter);
println!("Thread received data: {}", data);
if sender.send(data).is_err() {
break
}
counter += 1;
thread::sleep(std::time::Duration::from_millis(100));
}
});
(thr, Some(receiver))
}
As mentioned above, the only error remaining is that application.connect_activate() takes an Fn closure, the current implementation is FnMut.
The error message is:
error[E0596]: cannot borrow `receiver` as mutable, as it is a captured variable in a `Fn` closure
--> src/main.rs:17:31
|
17 | build_ui(application, receiver.take().unwrap())
| ^^^^^^^^ cannot borrow as mutable
So you cannot use "receiver" mutably, which is necessary for you to take() its contents.
But if you wrap the receiver inside a Cell, then you can access the immutable Cell's contents mutably. So add this line directly after the line with start_communication_thread():
let receiver = Cell::new(receiver);
There might be some more correct answer as I am only a beginner at Rust, but at least it seems to work.
Please note that this changes the take() call to be called against the Cell instead of Option, whose implementation has the same effect, replacing the Cell's contents with None.
Related
Unfortunately the tutorial and documentation for futures_signals doesn't show how to make the code behind the future actually execute.
I have tried using:
use futures_signals::signal::Mutable;
use futures_signals::signal::SignalExt; //for Iterator trait (gives for_each)
use futures::executor::LocalPool;
fn main(){
let my_state = Mutable::new(5);
let future = my_state.signal().for_each(|value| {
// This code is run for the current value of my_state,
// and also every time my_state changes
println!("{}", value);
async {}
});
println!("Awaiting...");
let mut pool = LocalPool::new();
pool.run_until(future);
println!("Done!");
}
This prints the "5", but then blocks forever. It does not print "Done!".
Why does it not see that the future has completed?
To expand upon jmbs comment, the future will only complete when the Mutable that returned it is dropped. This is because the Mutable can change state until it is dropped, and the callback will be called every time Mutable changes. The future is only complete when no more callbacks can be called.
See below for a fully working example:
use futures_signals::signal::Mutable;
use futures_signals::signal::SignalExt; //for Iterator trait (gives for_each)
use futures::executor::LocalPool;
use std::thread;
use futures::join;
fn main(){
//create my_state, and a clone that will be passed to the thread
let my_state = Mutable::new(5);
let my_state_shared = my_state.clone();
//increment my_state by 1 in a loop, until it reaches 10
thread::spawn(move || {
loop {
my_state_shared.set(my_state_shared.get() + 1);
thread::sleep(std::time::Duration::from_secs(1));
if my_state_shared.get() == 10 {
break;
}
}
});
//create observers
let obs_a_future = my_state.signal().for_each(|value| {
println!("Observer A {}", value);
async {}
});
let obs_b_future = my_state.signal().for_each(|value| {
println!("Observer B {}", value);
async {}
});
drop(my_state);
//run the app
let mut pool = LocalPool::new();
pool.run_until( async {
join!(obs_a_future, obs_b_future);
});
println!("!");
}
I have simple client/server application. I am receiving message on the server side from client but I want to send that response to the channel from server to other file and I am receiving error "borrowed value does not live long enough".
I have searched in the stack overflow for similar previous questions but not getting enough understanding of lifetime. Is there a good documentation or if simple example available on this topic?
For now if someone can help me to fix this code (may be edit the portion of code which needs to fix) that would be helpful.
Thanks in advance.
Server side:
use std::os::unix::net::UnixDatagram;
use std::path::Path;
fn unlink_socket (path: impl AsRef<Path>) {
let path = path.as_ref();
if Path::new(path).exists() {
let result = std::fs::remove_file(path);
match result {
Err(e) => {
println!("Couldn't remove the file: {:?}", e);
},
_ => {}
}
}
}
pub fn tcp_datagram_server() {
pub static FILE_PATH: &'static str = "/tmp/datagram.sock";
let (tx, rx) = mpsc::channel();
let mut buf = vec![0; 1024];
unlink_socket(FILE_PATH);
let socket = match UnixDatagram::bind(FILE_PATH) {
Ok(socket) => socket,
Err(e) => {
println!("Couldn't bind: {:?}", e);
return;
}
};
println!("Waiting for client to connect...");
loop {
let received_bytes = socket.recv(buf.as_mut_slice()).expect("recv function failed");
println!("Received {:?}", received_bytes);
let received_message = from_utf8(buf.as_slice()).expect("utf-8 convert failed");
tx.clone().send(received_message);
}
}
fn main() {
tcp_datagram_server();
}
client side:
use std::sync::mpsc;
use std::os::unix::net::UnixDatagram;
use std::path::Path;
use std::io::prelude::*;
pub fn tcp_datagram_client() {
pub static FILE_PATH: &'static str = "/tmp/datagram.sock";
let socket = UnixDatagram::unbound().unwrap();
match socket.connect(FILE_PATH) {
Ok(socket) => socket,
Err(e) => {
println!("Couldn't connect: {:?}", e);
return;
}
};
println!("TCP client Connected to TCP Server {:?}", socket);
loop {
socket.send(b"Hello from client to server").expect("recv function failed");
}
}
fn main() {
tcp_datagram_client();
}
Error I am getting
error[E0597]: `buf` does not live long enough
--> src/unix_datagram_server.rs:38:42
|
38 | let received_message = from_utf8(buf.as_slice()).expect("utf-8 convert failed");
| ^^^ borrowed value does not live long enough
...
41 | }
| -
| |
| `buf` dropped here while still borrowed
| borrow might be used here, when `tx` is dropped and runs the `Drop` code for type `std::sync::mpsc::Sender`
|
= note: values in a scope are dropped in the opposite order they are defined
error: aborting due to previous error; 8 warnings emitted
For now if someone can help me to fix this code (may be edit the portion of code which needs to fix) that would be helpful.
Well the message seems rather clear. send does exactly what it says it does, it sends the parameter through the channel. This means the data must live long enough and remain valid "forever" (it needs to be alive and valid in the channel, as well as when fetched from it by the receiver).
That is not the case here. rustc can't understand that the function never returns, and it can panic anyway which will end up the same: the function will terminate, which will invalidate buf. Since received_message borrows buf, that means received_message can't be valid after the function has terminated. But at that point the message would still be in the channel waiting to be read (or retrieved by the receiver doing who knows what).
Therefore your construction is not allowed.
A second issue is that you're overwriting the buffer data on every loop, which has the same effect of breaking the message you sent during the previous iteration, and thus is not correct either. Though Rust won't let you do that either: if you work around the first error it will tell you that there's an outstanding shared borrow (the message sent through the channel) so you can't modify the backing buffer in the following iteration.
The solution is quite simple: have each iteration create an owned string (copying the current iteration's message) and send that through the channel:
tx.clone().send(received_message.to_string());
Also, these are more style / inefficiency remarks but:
The clone() on tx is completely redundant. The point of having a sender that is Clone is being able to send from multiple threads (hence mp in the channel name, that's for multiple producers). Here you have a single thread, the original sender works fine.
.as_slice() and .as_mut_slice() are rarely used unless necessary, which they aren't here: array references coerce to slices, so you can just use &mut buf and &buf. And why are you calling Path::new on something that's already a path? It doesn't do anything but it's not useful either.
It is rather annoying that your snippet is missing multiple imports and thus doesn't even compile as is.
From more of a unixy perspective, errors are usually printed on stderr. In Rust, eprintln does that for you (otherwise working in the same way println does). And I don't understand the purpose of marking a lexically nested static pub. Since the static is inside the function it's not even visible to the function's siblings, to say nothing of external callers. As a result I'd end up with this:
use std::os::unix::net::UnixDatagram;
use std::path::Path;
use std::sync::mpsc;
use std::str::from_utf8;
fn unlink_socket (path: impl AsRef<Path>) {
let path = path.as_ref();
if path.exists() {
if let Err(e) = std::fs::remove_file(path) {
eprintln!("Couldn't remove the file: {:?}", e);
}
}
}
static FILE_PATH: &'static str = "/tmp/datagram.sock";
pub fn tcp_datagram_server() {
unlink_socket(FILE_PATH);
let socket = match UnixDatagram::bind(FILE_PATH) {
Ok(socket) => socket,
Err(e) => {
eprintln!("Couldn't bind: {:?}", e);
return;
}
};
let (tx, _) = mpsc::channel();
let mut buf = vec![0; 1024];
println!("Waiting for client to connect...");
loop {
let received_bytes = socket.recv(&mut buf).expect("recv function failed");
println!("Received {:?}", received_bytes);
let received_message = from_utf8(&buf).expect("utf-8 convert failed");
tx.send(received_message.to_string());
}
}
There's a hint in the compiler message, that values in a scope are dropped in the opposite order they are defined in, and in the example, buf is defined after tx, which means it will be dropped before tx. Since a reference to buf (in the form of received_message) is passed to tx.send(), then buf should live longer that tx, and therefore switching the definition order will fix this particular error (ie. switch lines 19 and 20).
I'm creating a basic Minecraft server in Rust. As soon as a player logs in to my server, I need to send a KeepAlive packet every 20 seconds to ensure the client is still connected.
I thought this would be solved by spawning a new thread that sends the packet after sleeping 20 seconds. (line 35). Unfortunately, the Server type doesn't implement Copy.
Error
error[E0382]: borrow of moved value: `server`
--> src/main.rs:22:9
|
20 | let mut server = Server::from_tcpstream(stream).unwrap();
| ---------- move occurs because `server` has type `ozelot::server::Server`, which does not implement the `Copy` trait
21 | 'listenloop: loop {
22 | server.update_inbuf().unwrap();
| ^^^^^^ value borrowed here after move
...
35 | thread::spawn(move || {
| ------- value moved into closure here, in previous iteration of loop
Code:
use std::thread;
use std::io::Read;
use std::fs::File;
use std::time::Duration;
use std::io::BufReader;
use ozelot::{Server, clientbound, ClientState, utils, read};
use ozelot::serverbound::ServerboundPacket;
use std::net::{TcpListener, TcpStream};
fn main() -> std::io::Result<()> {
let listener = TcpListener::bind("0.0.0.0:25565")?;
for stream in listener.incoming() {
handle_client(stream?);
}
Ok(())
}
fn handle_client(stream: TcpStream) {
let mut server = Server::from_tcpstream(stream).unwrap();
'listenloop: loop {
server.update_inbuf().unwrap();
let packets = server.read_packet().unwrap_or_default();
'packetloop: for packet in packets {
match packet {
//...
ServerboundPacket::LoginStart(ref p) => {
//...
//send keep_alive every 20 seconds
thread::spawn(move || {
thread::sleep(Duration::from_secs(20));
send_keep_alive(server)
});
fn send_keep_alive(mut server: Server) {
server.send(clientbound::KeepAlive::new(728)).unwrap();
}
//...
},
//...
_ => {},
}
}
thread::sleep(Duration::from_millis(50));
}
}
Notice how most of the functions in ozelot::Server take &mut self as a parameter. This means that they are called on a mutable reference to a ozelot::Server.
From Rust docs:
you can only have one mutable reference to a particular piece of data in a particular scope
The issue is - how can we share ozelot::Server between the main thread and the new thread?
A lot of things in std::sync module solve exactly these kinds of problems. In your case, you want read access from the main thread and write access from the thread calling send_keep_alive. This calls for Mutex - exclusive read/write access at a time, and
Wrap the server in an Arc<Mutex>:
use std::sync::{Arc, Mutex};
// --snip--
fn handle_client(stream: TcpStream) {
let mut server = Server::from_tcpstream(stream).unwrap();
let mut server = Arc::new(Mutex::new(server));
Move a clone of Arc into the thread, and lock the Mutex to gain access:
let server = Arc::clone(server);
thread::spawn(move || {
thread::sleep(Duration::from_secs(20));
send_keep_alive(&mut server)
});
And make send_keep_alive receive server by mutable reference:
fn send_keep_alive(server: &mut Arc<Mutex<Server>>) {
loop {
let mut server = server.lock().unwrap();
server.send(clientbound::KeepAlive::new(728)).unwrap();
}
}
I am trying to pass the scheduler to a structure which will be used by a newly spawned thread. All of this needs to happen in a loop:
// Custom structure
struct CSlice<'a> {
scheduler: &'a mut StandaloneScheduler
}
impl<'a> CSlice<'a> {
fn start(self)
{
println!("Start slice");
unsafe {
control_nf(self.scheduler); // It gets passed on and on to different functions.
}
}
}
fn main() {
for i in 0..max_slices {
let mut sched = StandaloneScheduler::new();
let mut slice = CtrlSlice {
scheduler: &mut sched}; // Error (Temp value/ Cannot borrow here)
}
thread::spawn(move || slice.start());
}
}
What am I doing wrong? I tried cloning but Scheduler does not implement Clone. I know that the reference goes out of scope while passing it to the function but I'm not sure how to fix it.
I am reading a string from a file, splitting it by lines into a vector and then I want to do something with the extracted lines in separate threads. Like this:
use std::fs::File;
use std::io::prelude::*;
use std::thread;
fn main() {
match File::open("data") {
Ok(mut result) => {
let mut s = String::new();
result.read_to_string(&mut s);
let k : Vec<_> = s.split("\n").collect();
for line in k {
thread::spawn(move || {
println!("nL: {:?}", line);
});
}
}
Err(err) => {
println!("Error {:?}",err);
}
}
}
Of course this throws an error, because s will go out of scope before the threads are started:
s` does not live long enough
main.rs:9 let k : Vec<_> = s.split("\n").collect();
^
What can I do now? I've tried many things like Box or Arc, but I couldn't get it working. I somehow need to create a copy of s which also lives in the threads. But how do I do that?
The problem, fundamentally, is that line is a borrowed slice into s. There's really nothing you can do here, since there's no way to guarantee that each line will not outlive s itself.
Also, just to be clear: there is absolutely no way in Rust to "extend the lifetime of a variable". It simply cannot be done.
The simplest way around this is to go from line being borrowed to owned. Like so:
use std::thread;
fn main() {
let mut s: String = "One\nTwo\nThree\n".into();
let k : Vec<String> = s.split("\n").map(|s| s.into()).collect();
for line in k {
thread::spawn(move || {
println!("nL: {:?}", line);
});
}
}
The .map(|s| s.into()) converts from &str to String. Since a String owns its contents, it can be safely moved into each thread's closure, and will live independently of the thread that created it.
Note: you could do this in nightly Rust using the new scoped thread API, but that is still unstable.