11 个版本

0.1.0-alpha.112021 年 4 月 23 日
0.1.0-alpha.92021 年 4 月 12 日
0.1.0-alpha.32021 年 4 月 7 日

#987并发

每月 47 次下载
音频设备 中使用

MIT/Apache

55KB
671

ste

Documentation Crates Actions Status

一个拥有一些小技巧的单线程执行器。

这个库主要是为在 音频 中以低延迟方式与单个后台线程交互而编写的,但也可以作为通用库用于其他任何目的。

稳健性警告:此包使用了大量的 不安全 功能。一些技巧在使用前需要进行严格的安全性检查,以确保在生产环境中可靠使用。

默认情况下,通过 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