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
41KB
738 行
已弃用
一开始使用这个crate可能就是一个错误。
breadthread
breadthread
提供了一个获取面包的线程。
某些API是不安全的,但在线程安全的环境中使用它们将很棒,因为某些运行时要求数据为Send
。 breadthread
提供了一个将这项工作导出到另一个线程的机制。
许可证
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());
请注意,BreadThread
和Driver
通过生命周期进行参数化,在这个例子中是'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
,它由以下内容组成
- 一个隐含为
Send
和Sync
的thread_safe_value
。 - 一个可能不是这些之一的
thread_unsafe_value
。一旦value
返回,此值将被封装在Object
中,这实际上允许它被发送到其他线程,但只能在驱动线程中使用。要再次使用此值,将值传递到bt.run()
方法中,以替换空元组,并且可以再次以原始形式使用。可以使用此策略返回Object
的元组和切片。请注意,此类值必须实现Compatible
。 deleted_values
由要从中删除的值组成,这些值位于线程的内部银行中,该银行跟踪对其有效的值。默认情况下,返回的值被添加到“有效”列表中,因此如果您不打算再次使用该值,可以将其添加到deleted_values
列表中。
value
是类型Value
,解析为包含thread_safe_value
和thread_unsafe_value
的安全版本的元组。它可以通过以下三种方式之一解析
- 使用
value.resolve()
轮询其是否已解析。 - 通过挂起线程等待它解析,使用
value.wait()
。 - 启用
async
功能后,Value
实现了Future
。
安全性
使用tag
确保面包线程只会与其标记为有效的值相关联。只要两个线程没有相同的标记,此验证将在编译时完成,而唯一真正的开销在于从两个线程发送和接收值。
如果创建了具有相同标记的多个线程,则默认情况下库会恐慌。如果不想有这种行为,请启用fallback
功能。相反,当两个线程共享一个标记时,它们将手动跟踪哪些值对哪个线程是有效的。
no_std
默认启用std
功能。如果没有std
,则此crate仅依赖于alloc
crate。但是,对外部和内部都进行了某些更改。
BreadThread::new()
、Driv(er::drive()
和Value::wait()
均不存在。- 内部,数据结构使用基于自旋锁的API,而不是基于系统同步的API。这种行为通常是不希望的。
除非在no_std
环境中使用此crate是必要的,否则建议使用std
功能。
依赖关系
~1–27MB
~352K SLoC