【问题标题】:Wait for backend thread to finish after application.run in Rust在 Rust 中的 application.run 之后等待后端线程完成
【发布时间】:2021-03-29 12:12:01
【问题描述】:

我想等待一个后端线程(Like this,但在我的情况下,后端管理一个我想在应用程序实际退出之前正确关闭的数据库)在application.run() 完成后完成(例如加入它)。

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

【问题讨论】:

  • 可以链接到外部网站,但为了让问题对未来有用,请在问题本身中包含您的minimal reproducible example
  • edit 您的问题并粘贴您所得到的准确和完整的错误——这将帮助我们了解问题所在,以便我们能够提供最好的帮助。有时试图解释错误消息很棘手,实际上错误消息的不同部分很重要。请使用直接运行编译器的消息,而不是 IDE 生成的消息,它可能会尝试为您解释错误。

标签: multithreading rust gtk


【解决方案1】:

错误信息是:

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 的内容替换为None

【讨论】:

  • 它似乎有效 — 你为什么不能确定它有效?也许这意味着 OP 没有提供minimal reproducible example?希望您不会浪费时间尝试回答一个没有明确说明的问题。
  • 没有浪费时间,因为我自己在这里学到了很多东西。我不完全了解FnFnMut 之间的区别以及为什么api 会选择使用Fn 从而阻止可变使用捕获的变量。 api 也有可能意外地受到不必要的限制,并且也可能使用了FnMut。我不能说。所以我不确定我的答案是否正确。
猜你喜欢
  • 2013-04-25
  • 1970-01-01
  • 1970-01-01
  • 2017-05-15
  • 1970-01-01
  • 1970-01-01
  • 2011-04-24
  • 1970-01-01
相关资源
最近更新 更多