#stm #transactional-memory #atomic #transaction #lock-free #read-write

stm-core

软件事务内存的实现。STM 允许组合原子操作。STM-core 实现了 STM 使用的骨架。STM 包添加了有用的数据结构。

1 个不稳定版本

使用旧的 Rust 2015

0.4.0 2018年3月29日

#9 in #stm

每月 49 次下载
2 个包中使用 (通过 stm)

MIT/Apache

54KB
787

软件事务内存 构建状态

此库实现了 软件事务内存,通常缩写为 STM。

其设计紧密遵循 Haskell 的 STM 库。阅读 Simon Marlow 的 Parallel and Concurrent Programming in Haskell 获取更多信息。特别是关于 性能 的章节对于在 Rust 中使用 STM 也非常重要。

与锁不同,软件事务内存是可组合的。它通常通过在日志中编写所有读取和写入操作来实现。当操作完成且所有使用的 TVar 保持一致时,写入作为一个单一的原子操作提交。否则,计算会重复。这可能会导致饥饿,但避免了常见的错误来源。

与锁不同,软件事务内存不会在 panic 时提交。STM 通过从不提交 panic 来确保一致性。

在 STM 中 panic 不会污染 TVar。STM 通过从不提交 panic 来确保一致性。

用法

您应仅使用可安全使用的函数。

除了来自此库的原子变量之外,不要有副作用。特别是软件事务内存中的互斥锁或其他阻塞机制是危险的。

您可以通过调用 atomically 来运行顶层原子操作。

use stm::atomically;
atomically(|trans| {
    // some action
    // return value as `Result`, for example
    Ok(42)
});

atomically 的调用不应嵌套。

要在一个原子操作内部运行另一个原子操作,传递一个 Transaction 的可变引用,并在结果上调用 try! 或使用 ?。您不应自己处理错误,因为这会破坏一致性。

use stm::{atomically, TVar};
let var = TVar::new(0);

let x = atomically(|trans| {
    var.write(trans, 42)?; // Pass failure to parent.
    var.read(trans) // Return the value saved in var.
});

println!("var = {}", x);

STM 安全性

在 Rust 考虑安全的意义上,软件事务内存是完全安全的。尽管如此,在使用软件事务内存时,您仍应遵守多个规则。

  • 不要运行有副作用的代码,尤其是没有IO的代码,因为stm在检测到不一致的状态时会重复计算。如果必须,请返回一个闭包。
  • 除非你完全清楚自己在做什么,否则不要自己处理错误类型。使用Transaction::or来组合替代路径。始终调用try!?,永远不要忽略StmResult
  • 不要在另一个atomically内部运行。因为atomically设计用于有副作用,所以它会破坏stm的假设。嵌套调用会在运行时被检测到,并以panic的方式处理。当你在函数的内部使用STM时,通过将&mut Transaction作为参数并返回StmResult<T>来在公共接口中表达它。调用者可以安全地将它组合成更大的块。
  • 不要混合锁和事务。你的代码很容易在不可预测的情况下死锁或变慢。
  • 不要使用内部可变性来更改TVar的内容。

速度

通常尽量保持你的原子块尽可能小,因为花费的时间越多,与其他线程发生冲突的可能性就越大。对于STM,读取TVar相当慢,因为每次都需要在日志中查找。每个使用的TVar都会增加冲突的机会。因此,你应该将访问变量的数量保持在所需的最小范围内。

许可证

根据您的选择,许可如下

任选其一。

贡献

除非你明确声明,否则根据Apache-2.0许可证定义的,你故意提交的任何贡献,都应按上述方式双许可,不附加任何额外条款或条件。

依赖关系

~1MB
~15K SLoC