#mutex #linux #semaphore #lock #classic #sync #cyclic-barrier

classic-sync

使用经典 Linux Mutex 系统提供 ReentrantLock、Semaphore 和 CyclicBarrier

3 个版本

0.4.4 2023 年 8 月 14 日
0.4.3 2023 年 8 月 14 日
0.4.2 2023 年 8 月 14 日

#821并发

Apache-2.0

270KB
9K SLoC

超简单的 ReentrantLock、Semaphore 和 CyclicBarrier 实现

实现是 Rust 的 C 绑定的包装器。

它在 Linux 上进行了测试。理论上所有具有 CC 的系统都应能工作,未在 Windows 上测试。

最重要的是以下优势

  • 它们都是 Sync
  • 它们都是 Unpin
  • 它们都是 Send
  • 它们不需要可变即可锁定!

Semaphore

use classic_sync::semaphore::Semaphore;

let sem = Semaphore::new(10); // create semaphore with 10 concurrent access
let sem = Arc::new(sem); // Usage of Sem can be direct (rare) or by Arc (common)
let sem1 = Arc::clone(&sem); // use in other threads are done by Arc::clone

// Using semaphore
sem1.p();  // acquire token to access resource
// use resource
sem1.v(); // release resource

// Droping Arc<Semaphore> won't release all waiting threads. You have to take care of that yourself.
// After last reference is dropped, the Semaphore is destroyed. If you still have threads waiting, 
// behaivor is same as sem_t in c.
let acquire_ok:bool = sem1.p_timeout(Duration::from_secs(1)); // try to acquire with 1 seconds timeout
if acquire_ok {
    // use resource
} else {
    // acquire timeout, try again
}

ReentrantLock

没有特别之处,它只是 Semaphore 的方便包装器。您可以使用 Semaphore::new(1) 达到相同的目的

use classic_sync::lock::ReentrantLock;

let lock = ReentrantLock::new(); // create exclusive lock
let lock = Arc::new(lock); // Usage of Lock can be direct (rare) or by Arc (common)
let lock1 = Arc::clone(&lock); // use in other threads are done by Arc::clone

// Using semaphore
lock1.lock();  // acquire exclusive access to resource
// use resource
lock1.unlock(); // release resource

let acquire_ok:bool = lock1.try_lock(Duration::from_secs(1)); // try to acquire with 1 seconds timeout
if acquire_ok {
    // use resource
} else {
    // acquire timeout, try again
}

CyclicBarrier

如果您想要同步所有线程一起开始某件事,这是您的工具。

它是 pthread_barrier_t 对象的包装器。

use classic_sync::cyclic_barrier::CyclicBarrier;

let barrier = CyclicBarrier::new(10); // create barrier that can wait for 10 parties
let barrier = Arc::new(barrier); // Usage of Barrier can be direct (rare) or by Arc (common)
let barrier1 = Arc::clone(&barrier); // use in other threads are done by Arc::clone

// Using Barrier
barrier.wait();  // after this returns all parties are ready

// Check if this is the last one enters the party
let wr = barrier.wait();
if let Some(_) = wr {
    // This one is the last one enters the barrier
}

// after wait succeeded, barrier can be reused actually... it goes back to the pre-wait state again.

依赖关系

~230KB