#thread #called #mutex #rwlock #once

one_at_a_time_please

用于函数调用的序列化

2 个稳定版本

1.0.1 2022年6月4日

#738并发

MIT 许可证

8KB
65

一次一个,请

将函数标记为 #[one_at_a_time],然后一次只能有一个线程调用它们。这是对函数调用进行快速且简单的同步。

它是做什么的?

假设你有很多函数。它们将从多个线程中被调用。你只想一次调用其中一个。当这种情况发生时,你希望其他的都处于阻塞状态。

例如;你有一堆测试。你希望并行运行它们,除了四个应该串行运行的。

(单线程递归仍然是允许的。)

它是如何工作的?

内部有一个大锁。标记为 one_at_a_time 的函数将获取这个大锁。当他们拥有它时,其他人就会被阻塞。

API

  • #[one_at_a_time] -- 附加到函数的注解。带有此注解的函数一次只能在一个线程上调用。否则它们(礼貌地)等待直到轮到它们。
  • one_at_a_time() -- 一个辅助函数,你可以自己用代码实现。你调用它,传入一个lambda表达式,然后它将(礼貌地)等待锁空闲,然后运行。
  • OneAtATime - 所有其他API共享一个巨大的锁。这是一个结构体,允许你创建自己的锁,并用它来代替。

示例

#[one_at_a_time]

use ::one_at_a_time_please::one_at_a_time;

/// This __cannot__ be called from different threads at the same time.
#[one_at_a_time]
fn add(a: u32, b: u32) -> u32 {
    a + b
}

one_at_a_time<F>(f: FnOnce() ->R) ->F

use ::one_at_a_time_please::one_at_a_time;

/// This __can__ be called from different threads at the same time ...
fn some_function(a: u32, b: u32) -> u32 {
    /// but this __cannot__ be called from different threads.
    one_at_a_time(move || {
        a + b
    })
}

struct OneAtATime

use ::one_at_a_time_please::one_at_a_time;
use ::std::sync::Arc;

/// This example is for showing that you can make your own lock,
/// and block on that.
///
/// This is a different lock to what `#[one_at_a_time]` uses.
/// It's behaviour will not overlap with them.
#[one_at_a_time]
fn some_function(a: u32, b: u32) -> u32 {
    let oaat = Arc::new(OneAtATime::new());

    for i in 0 .. 10 {
        let thread_local_oaat = oaat.clone();
        let thread = spawn(move || {
            for _ in 0..10 {
                thread_local_oaat.call(|| {
                    // do stuff here
                });
            }
        });
    }
}

高级示例

在测试中提供了一个(可怕的)不安全计数器的示例。其中使用 #[one_at_a_time] 使其调用变得安全。

您可以在 tests/unsafe_counter.rs 中找到它。

依赖关系

~0.4–5.5MB
~13K SLoC