よをこめてねむる

  • ホーム
  • Tauri2のChannelでウィンドウがビジーになり動かなくなる時の対処

Tauri2のChannelでウィンドウがビジーになり動かなくなる時の対処

  • 作成日: 2025-09-11
  • 更新日: 2025-09-11
  • カテゴリ: Tauri2

Tauri2でプログレスバーなどを実装するときにChannelという通信形態を使うことがあります。
私の場合はメインウィンドウからサブウィンドウを出して、そのサブウィンドウで長時間かかるバックエンド関数を実行し、その進捗をサブウィンドウ上で表示するというケースでした。
単純に関数をinvokeするだけだとサブウィンドウがビジーになります。これはinvokeで制御がバックエンドに移って返ってこなくなるからです。
これに対処するにはスレッドを起動してバックエンド関数を別スレッドで実行する必要があります。

#[tauri::command]  
pub fn heavy_func(  
    app: AppHandle,  
    on_event: Channel<HeavyFuncEvent>,  
) -> Result<(), Error> {  
    std::thread::spawn(|| {  
        heavy_func_process(app, on_event).unwrap();  
    });  
    Ok(())  
}  

上記のように長時間かかる関数をstd::thread::spawn()でスポーンすると、制御がサブウィンドウに戻りました。

ただしスレッドをjoinせずに切り離すと、メモリリークする可能性があります。
スレッドをjoinする場合は以下のようなコードを書きます。

    let handler = std::thread::spawn(|| {  
        heavy_func_process(app, on_event).unwrap();  
    });  
    handler.join().unwrap();  

ただしjoinする場合はサブスレッドが終了するまで待機するので、サブウィンドウはビジー状態になります。
デタッチしてメモリリークを許容する設計もありだと思います。サブウィンドウのクローズなどを検出して、バックエンドにイベントを送り、デタッチしたサブスレッドの終了処理を行えばメモリリークは回避できるでしょう。

pub fn heavy_func_process(app: AppHandle, Channel<HeavyFuncEvent>) -> Result<(), Error> {  
    // フロントエンドからstop_heavy_funcイベントを受信したら、  
    app.listen("stop_heavy_func", |event| {  
        // フラグを折ったりしてループ処理を終了させる。  
    })  
}