11 个版本
0.1.0-alpha.11 | 2021 年 4 月 23 日 |
---|---|
0.1.0-alpha.9 | 2021 年 4 月 12 日 |
0.1.0-alpha.3 | 2021 年 4 月 7 日 |
#987 在 并发
每月 47 次下载
在 音频设备 中使用
55KB
671 行
ste
一个拥有一些小技巧的单线程执行器。
这个库主要是为在 音频 中以低延迟方式与单个后台线程交互而编写的,但也可以作为通用库用于其他任何目的。
稳健性警告:此包使用了大量的 不安全 功能。一些技巧在使用前需要进行严格的安全性检查,以确保在生产环境中可靠使用。
默认情况下,通过 submit 方法访问底层线程。这将在任务执行期间阻塞当前线程,允许后台线程访问作用域内的变量。如下面的 n
所示。
let thread = ste::spawn();
let mut n = 10;
thread.submit(|| n += 10)?;
assert_eq!(20, n);
thread.join()?;
使用标签限制线程访问
此库提供了一种构造 Tag 的能力,它与创建它的线程唯一相关联。然后可以使用它来确保数据只能被一个线程访问。
这很有用,因为许多 API 需要实例 线程局部性,其中实例只能安全地由创建它们的线程使用。这是一个低级工具,我们提供它允许为其他情况下不可 Send
的类型安全地实现 !Send
。
请注意,正确使用 Tag 很困难,错误使用会有严重的安全影响。在使用前务必仔细研究其文档。
struct Foo {
tag: ste::Tag,
}
impl Foo {
fn new() -> Self {
Self {
tag: ste::Tag::current_thread(),
}
}
fn say_hello(&self) {
self.tag.ensure_on_thread();
println!("Hello World!");
}
}
let thread = ste::spawn();
let foo = thread.submit(|| Foo::new())?;
thread.submit(|| {
foo.say_hello(); // <- OK!
})?;
thread.join()?;
在创建它的线程外部使用 say_hello
是不正确的,并将引发 panic 以防止竞态条件访问
let thread = ste::spawn();
let foo = thread.submit(|| Foo::new())?;
foo.say_hello(); // <- Oops, panics!
thread.join()?;
已知的非安全和稳健性问题
以下列出了此库当前具有的不安全使用和已知的稳健性问题。在发布 alpha 版本之前,必须解决稳健性问题。
指向栈局部地址的指针
为了高效地在调用submit的线程和后台线程之间共享数据,后台线程会引用调用线程中大量栈局部数据,这涉及到不少unsafe
操作。
虽然应该可以使其使用安全的方式(这也是本库的期望),但如果后台线程继续执行一个与submit调用者不再同步的任务,可能会最终引用到不再有效(已释放后使用)或包含其他内容(脏数据)的数据。
标签重用
Tag容器当前使用的是基于与每个Thread关联的分配内存块地址的标签。然而,如果一个Thread被关闭,并且后来重新创建,存在一定风险,这可能会重用现有的内存地址。
内存地址相当容易使用,因为它们成本低且易于访问。然而,因此可能希望为每个线程使用生成的ID,例如,在无法保证唯一性时终止程序。
许可证:MIT/Apache-2.0
依赖项
~2–3.5MB
~49K SLoC