#thread #thread-safe #systems #api #run-time #bread #unsafe

no-std breadthread

GUI抽象;添加一个线程控制器,有助于获取一些面包

4个版本

0.1.4 2023年3月30日
0.1.3 2021年8月21日
0.1.1 2021年6月15日
0.1.0 2021年6月15日

#unsafe中排名第123

MIT/Apache

41KB
738

已弃用

一开始使用这个crate可能就是一个错误。

breadthread

Build Status crates.io docs.rs

breadthread提供了一个获取面包的线程。

某些API是不安全的,但在线程安全的环境中使用它们将很棒,因为某些运行时要求数据为Sendbreadthread提供了一个将这项工作导出到另一个线程的机制。

许可证

MIT/Apache2许可证


lib.rs:

一个允许在指定的

动机

有很多API是不安全的。在设计这个crate时,我想到了Windows winuser窗口API,但还有很多其他的。虽然小型程序可能能够避开线程不安全,但对于需要Safe边界的运行时的大型程序来说,可能不行。

通常,这些程序将不得不求助于复杂系统来确保代码在一个指定的“本地”线程或线程池上运行。这个crate的目标是通过提供一个允许在指定线程上执行线程不安全代码的运行时来简化这些系统。

用法

首先,创建一个类型,用作 [Tag]。此类型将在编译时用于唯一标识运行时将在其上运行的线程。这确保了原生于一个线程的值不会在另一个线程上使用。

任何 'static 类型都可以用作标记,建议使用零大小类型。

struct MyTag;

然后,创建一个 BreadThread 类型。这是指令发送到的运行时。要创建一个新的线程来运行指令,请使用 new 方法。

use breadthread::BreadThread;

let bt = BreadThread::<'static, MyTag>::new();

但是,如果您已经有了想利用的系统(例如,一个专门的线程池如rayon),您可以使用 undriven() 方法创建一个 BreadThread 和一个 Driver。您可以通过在 Driver 上调用 drive() 将线程或线程类似的任务转换成驱动线程。

let (bt, driver) = BreadThread::<'static, MyTag>::undriven();
my_runtime::spawn_task(move || driver.drive());

请注意,BreadThreadDriver通过生命周期进行参数化,在这个例子中是'static。生命周期用作我们发送给线程的指令的边界。如果您想发送借用其他数据的指令,请考虑使用此功能。

现在,我们可以调用BreadThread上的run方法来运行给定方法。


use breadthread::DirectiveOutput;

let input_value = 7;
let value = bt.run((), move |()| {
    let ret_ty = thread_unsafe_code(input_value);
    DirectiveOutput {
        thread_safe_value: (),
        thread_unsafe_value: ret_ty,
        deleted_values: vec![],
    }
});

bt.run()期望返回类型为DirectiveOutput,它由以下内容组成

  • 一个隐含为SendSyncthread_safe_value
  • 一个可能不是这些之一的thread_unsafe_value。一旦value返回,此值将被封装在Object中,这实际上允许它被发送到其他线程,但只能在驱动线程中使用。要再次使用此值,将值传递到bt.run()方法中,以替换空元组,并且可以再次以原始形式使用。可以使用此策略返回Object的元组和切片。请注意,此类值必须实现Compatible
  • deleted_values由要从中删除的值组成,这些值位于线程的内部银行中,该银行跟踪对其有效的值。默认情况下,返回的值被添加到“有效”列表中,因此如果您不打算再次使用该值,可以将其添加到deleted_values列表中。

value是类型Value,解析为包含thread_safe_valuethread_unsafe_value的安全版本的元组。它可以通过以下三种方式之一解析

  • 使用value.resolve()轮询其是否已解析。
  • 通过挂起线程等待它解析,使用value.wait()
  • 启用async功能后,Value实现了Future

安全性

使用tag确保面包线程只会与其标记为有效的值相关联。只要两个线程没有相同的标记,此验证将在编译时完成,而唯一真正的开销在于从两个线程发送和接收值。

如果创建了具有相同标记的多个线程,则默认情况下库会恐慌。如果不想有这种行为,请启用fallback功能。相反,当两个线程共享一个标记时,它们将手动跟踪哪些值对哪个线程是有效的。

no_std

默认启用std功能。如果没有std,则此crate仅依赖于alloccrate。但是,对外部和内部都进行了某些更改。

  • BreadThread::new()Driv(er::drive()Value::wait() 均不存在。
  • 内部,数据结构使用基于自旋锁的API,而不是基于系统同步的API。这种行为通常是不希望的。

除非在no_std环境中使用此crate是必要的,否则建议使用std功能。

依赖关系

~1–27MB
~352K SLoC