在 Rust 中等待后端线程在 application.run 之后完成
Wait for backend thread to finish after application.run in Rust
我想等待后端线程(Like this 但在我的例子中后端管理一个数据库,我想在应用程序实际退出之前正确关闭它)在 [= 之后完成(例如加入它) 12=] 已完成。
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))
}
如上所述,唯一剩下的错误是 application.connect_activate()
需要一个 Fn
闭包,当前的实现是 FnMut
.
错误信息是:
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
因此您不能可变地使用“receiver”,这对于您take()
其内容是必要的。
但是,如果将接收器包装在 Cell
中,则可以可变地访问不可变 Cell
的内容。所以直接在 start_communication_thread()
:
行之后添加这一行
let receiver = Cell::new(receiver);
可能会有一些更正确的答案,因为我只是 Rust 的初学者,但至少它似乎有效。
请注意,这会更改 take()
调用以针对 Cell
而不是 Option
,其实现具有相同的效果,替换 Cell
' s 内容 None
.
我想等待后端线程(Like this 但在我的例子中后端管理一个数据库,我想在应用程序实际退出之前正确关闭它)在 [= 之后完成(例如加入它) 12=] 已完成。
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))
}
如上所述,唯一剩下的错误是 application.connect_activate()
需要一个 Fn
闭包,当前的实现是 FnMut
.
错误信息是:
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
因此您不能可变地使用“receiver”,这对于您take()
其内容是必要的。
但是,如果将接收器包装在 Cell
中,则可以可变地访问不可变 Cell
的内容。所以直接在 start_communication_thread()
:
let receiver = Cell::new(receiver);
可能会有一些更正确的答案,因为我只是 Rust 的初学者,但至少它似乎有效。
请注意,这会更改 take()
调用以针对 Cell
而不是 Option
,其实现具有相同的效果,替换 Cell
' s 内容 None
.