在 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: &gtk::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.