#跨平台 #运行 #系统 #循环 #一致 #接口 #线程

irondash_run_loop

系统运行循环的一致、跨平台接口

8个版本 (4个破坏性更新)

0.5.0 2023年12月26日
0.4.0-dev.22023年11月29日
0.3.0 2023年7月28日
0.2.0 2023年7月1日
0.1.0 2022年11月15日

#336 in 异步

Download history 831/week @ 2024-03-14 1183/week @ 2024-03-21 1069/week @ 2024-03-28 1570/week @ 2024-04-04 1752/week @ 2024-04-11 1417/week @ 2024-04-18 1138/week @ 2024-04-25 1380/week @ 2024-05-02 1549/week @ 2024-05-09 2115/week @ 2024-05-16 1504/week @ 2024-05-23 1673/week @ 2024-05-30 1233/week @ 2024-06-06 1069/week @ 2024-06-13 1201/week @ 2024-06-20 627/week @ 2024-06-27

4,373每月下载量
2 crate 中使用

MIT 许可

135KB
3.5K SLoC

irondash_run_loop

此crate提供对系统运行循环的一致、跨平台接口。

获取当前线程的RunLoop

let run_loop = RunLoop::current();

如果没有与当前线程关联的RunLoop,则会创建一个。 RunLoop由特定于平台的实现支持

  • CFRunLoop在iOS和macOS上
  • ALooper在Android上
  • GMainContext在Linux上
  • HWND消息循环在Windows上

从其他线程调用RunLoop

RunLoop既不是 Send,也不是 Sync。与它的所有交互都必须在RunLoop所属的线程上执行。

要从其他线程与RunLoop交互,请使用 RunLoopSender

let run_loop = RunLoop::current();
let sender = run_loop.new_sender();

// sender is Sync, Send and Clone
thread::spawn(move||{
    println("Hello from other thread!");
    sender.send(||{
        println!("Back on RunLoop thread");
    });
});

在任何时候,无需RunLoop实例,您都可以请求发送器将闭包发送到主线程。为了使所有平台上的Dart应用程序都起作用,您的Dart应用程序必须依赖于irondash_engine_context插件。

thread::spawn(move||{
    let sender = RunLoop::sender_for_main_thread().unwrap();
    sender.send(||{
        println!("Back on main thread");
        // run_loop is main thread run loop
        let run_loop = RunLoop::current();
    });
});

依赖于irondash_engine_context插件是必要的,因为Rust代码可能是FFI插件的一部分,该插件从UI线程或其他后台隔离区加载,并且在某些平台上,如果没有在主线程上先做一些准备工作,就不可能跳回主线程(这由irondash_engine_context插件的本地代码部分提供便利)。

如果您想在不使用irondash_engine_context插件的情况下使用RunLoop,则可以在主线程上调用RunLoop::set_main_thread()作为RunLoop的第一个方法。

安排定时器

RunLoop也可以用来安排闭包的延迟执行

let run_loop = RunLoop::current();
let handle = run_loop.schedule(Duration::from_secs(10), || {
    println!("This will be printed after 10 seconds");
});

RunLoop::schedule 返回一个 Handle 实例。如果句柄在计时器执行之前被丢弃,计时器将被取消。如果您不希望这样,请在句柄上调用 detach

let run_loop = RunLoop::current();
self.run_loop(Duration::from_secs(10), || {
    println!("This will be printed after 10 seconds");
}).detach();

您还可以调用 handle.cancel() 来取消计时器,而无需丢弃句柄。

计时器不会重复。每个计划中的计时器最多只会执行一次。

异步支持

RunLoop 可以用作未来执行器

RunLoop::current().spawn(async move ||{
    RunLoop::current().wait(Duration::from_secs(10)).await;
    println("After 10 second delay");
});

// or use crate::spawn variant:

spawn(async move ||{
    RunLoop::current().wait(Duration::from_secs(10)).await;
    println("After 10 second delay");
});

由于未来是在属于 RunLoop 的单个线程上执行的,因此它们不需要是 Send

什么是主线程?

这在不同平台上略有不同。

  • 在 iOS 和 macOS 上,它是应用程序启动时创建的第一个线程。它是 pthread_main_np() 返回 1 的线程。
  • 在 Linux 上,对于 RunLoop 的目的而言,主线程类似于 iOS 和 macOS 的第一个线程。
  • 在 Android 上,存在主线程的概念(即 Looper.getMainLooper())。
  • 在 Windows 上,主线程是应用程序启动时创建的第一个线程,类似于 macOS 和 iOS。如果您在不同的线程上创建窗口并泵送消息循环,RunLoop::sender_for_main_thread() 将不会按预期工作。

依赖关系

~0.9–15MB
~142K SLoC