在 GTK4 事件循环中添加超时以接收蓝牙设备

问题描述 投票:0回答:1

我在使用 Rust 和 GTK4 编写自己的蓝牙客户端时遇到了问题。

这就是想法。我有一个主事件循环,我想添加一个超时来每 5 秒轮询一个新的蓝牙设备,因为 GTK4 只是一个同步库。我使用 bluer 编写了一个异步函数来枚举蓝牙设备。该程序在其自己的具有异步主函数的程序中运行良好。采用相同的功能并将其移动到具有基本 GTK UI 的更大项目中(出于某种原因)不会将任何设备推送到消息队列。

在此上下文中的消息队列是

Arc<Mutex<Vec<String>>>
。只是在线程之间共享一个标准的
Mutex
sync_channels
和普通通道也会出现这种情况。

主线程尝试锁定

Mutex
,读取它,然后使用
drop(Mutex)
释放锁定。主循环上的事件每 5 秒运行一次。其余时间,我们的异步函数锁定互斥体并尝试将设备名称推送到消息队列,以便主线程可以读取它。

这是我到目前为止的代码。

pub fn build_ui(app: Application) -> Application {
    app.connect_activate(move |app| {
        let mut queue = Arc::new(Mutex::new(Vec::<String>::new()));
        let mlayout = Grid::builder()
            .height_request(700)
            .width_request(200)
            .build();
        let text_buf = TextBuffer::new(None);
        let text_view = TextView::builder()
            .buffer(&text_buf)
            .width_request(200)
            .height_request(600)
            .vexpand(true)
            .build();
        let mwindow = ApplicationWindow::builder()
            .application(app)
            .resizable(false)
            .width_request(200)
            .height_request(700)
            .child(&mlayout)
            .build();
        let dev_list = Frame::builder()
            .height_request(700)
            .width_request(200)
            .vexpand(true)
            .child(&text_view)
            .build();
        let title = Label::builder()
            .label("Device List")
            .css_name("Title")
            .width_request(200)
            .height_request(50)
            .justify(gtk4::Justification::Center)
            .build();
        mlayout.attach(&title, 0, 0, 200, 50);
        mlayout.attach(&dev_list, 0, 50, 200, 1);
        mwindow.init_layer_shell();
        mwindow.set_anchor(Edge::Right, true);
        mwindow.set_anchor(Edge::Top, true);
        mwindow.present();
        let txqueue = Arc::clone(&queue);
        thread::spawn(move || async {
            blue_init(txqueue).await;
        });
        gtk4::glib::timeout_add_local(Duration::from_secs(5), move || {
            match queue.clone().try_lock() {
                Ok(dev) => {
                    println!("{:#?}", dev);
                    drop(dev);
                    ControlFlow::Continue
                }
                _ => ControlFlow::Continue,
            }
        });
    });

    app
}

pub async fn blue_init(queue: Arc<Mutex<Vec<String>>>) {
    let runtime = tokio::runtime::Builder::new_multi_thread()
        .enable_all()
        .build()
        .unwrap();
    runtime.spawn(async move {
        let session = Session::new().await.unwrap();
        let adapter = session.default_adapter().await.unwrap();
        let discover = adapter.discover_devices().await.unwrap();
        pin_mut!(discover);
        while let Some(evt) = discover.next().await {
            match evt {
                AdapterEvent::DeviceAdded(addr) => {
                    let device = adapter.device(addr).unwrap();
                    let name = device.alias().await.unwrap();
                    match queue.try_lock() {
                        Ok(mut data) => {
                            data.push(name);
                            drop(data);
                        }
                        _ => {}
                    }
                }
                _ => {}
            }
        }
    });

如有任何帮助,我们将不胜感激。

linux rust bluetooth bluez gtk4
1个回答
0
投票
thread::spawn(move || async {
    blue_init(txqueue).await;
});

这不执行任何操作:它启动一个新线程来初始化 future,但从不轮询它并立即返回。所以你的

blue_init
函数永远不会被调用(尝试在其中添加
println
来亲自查看)。

相反,您应该从

async
的声明中删除
blue_init

pub fn blue_init (queue: Arc<Mutex<Vec<String>>>) {
    todo!();
}

并直接在线程中调用:

thread::spawn (move || blue_init (txqueue));
© www.soinside.com 2019 - 2024. All rights reserved.