#信号量 #同步 #Unix #信号 #同步 #无标准库 #API 绑定

无标准库 sem_safe

POSIX 信号量的安全使用(sem_postsem_wait 等)

3 个不稳定版本

新版本 0.1.1 2024年8月18日
0.1.0 2024年8月10日
0.0.1-pre2024年7月20日

172 in Unix API

Download history 57/week @ 2024-07-14 40/week @ 2024-07-21 1/week @ 2024-07-28 94/week @ 2024-08-04 30/week @ 2024-08-11

222 monthly downloads
Used in signals_receipts

Unlicense

29KB
228 lines

sem_safe

一个Rust风格的、直接的POSIX信号量接口,强制执行信号量的安全使用。

示例

use sem_safe::unnamed::Semaphore;
use std::{pin::Pin, thread};

static SEMAPHORE: Semaphore = Semaphore::new();

fn main() {
    let sem = Pin::static_ref(&SEMAPHORE);
    let sem = sem.init().unwrap();
    thread::spawn(move || sem.post().unwrap());
    sem.wait().unwrap();
}

动机

POSIX信号量,特别是sem_post函数,对于异步信号处理程序唤醒阻塞的线程非常有用,因为sem_post是异步信号安全的(相比之下,许多线程唤醒API,如通道,并不保证这一点)。信号处理程序仍然需要非常小心,确保它们所做的一切都是异步信号安全的(例如,仅使用原子类型将信号信息传递给其他线程),但sem_post提供了唤醒另一个线程的关键能力(例如,在正常上下文中进一步处理传递的信号信息,而不受异步信号安全的极端限制)。 (sem_post的少数替代方案之一是“self-pipe”技巧,其中从信号处理程序向管道写入,从另一端阻塞读取的线程,但这相当复杂(因为需要设置管道、关闭-on-exec、非阻塞写入等)。

信号处理并非唯一的使用场景。这个crate提供了一个C API的类似实现,可用于各种其他信号量使用场景。目前,仅支持“未命名”信号量的API,包括在多个进程间共享或仅在单个进程中私有的模式。对于“定时等待”和“命名”信号量的其他API可能在将来实现。

设计

根据Rust的方式安全地使用POSIX信号量面临的挑战,以及这个crate提供的解决方案包括

  • 要在多个线程间共享信号量,类型必须是Sync,这需要“内部可变性”。这个crate通过实现自己的抽象来覆盖UnsafeCell<libc::sem_t>来达到这一点,这也使得这种类型的值可以作为全局static项(不是mut)使用,这可能很方便;或者这种类型的值可以是有较短生命周期的局部变量,并且执行寿命安全。

  • sem_t类型的值必须从未初始化开始,然后通过调用sem_init()进行初始化,然后才能对sem_t应用其他操作。这个crate有独立的Semaphore和借用SemaphoreRef类型,以强制执行只能对初始化值的引用执行操作,并且引用只能在拥有值并初始化后获得。

  • 反初始化(sem_destroy())仅在丢弃拥有的Semaphore并且它被初始化时进行。如果有任何存在的SemaphoreRef,则会阻止丢弃,从而防止在仍有潜在使用位置时销毁信号量。

  • 不清楚在用sem_init()初始化后是否允许移动sem_t值。OpenIndiana手册页说,“复制”(地址将不同于初始化的位置)将是未定义的,这可能意味着移动的值也可能如此。这个crate使用Pin来强制初始化后不能移动值。

  • sem_init()必须只对一个sem_t执行一次。因为这个crate直接使用原子操作(因为这个crate是no_std),所以即使有额外的调用,也许是从多个线程并发调用,也强制执行这一点。

可移植性

这个crate已经在(目前仅限于x86_64)上确认可以构建并通过其测试。

  • BSD
    • FreeBSD 14.0
    • NetBSD 9.1
  • Linux
    • Alpine 3.18(使用musl)
    • Debian 12
    • NixOS 24.05
    • Ubuntu 23.10
  • Solaris
    • OpenIndiana 2023.10

它可能在其他POSIX操作系统上也能工作。如果没有,添加对其他POSIX操作系统的支持应该很容易,但可能需要对这个crate的条件编译和/或链接进行修改。

macOS 不支持

不幸的是,macOS不提供未命名的信号量API(违反了现代POSIX版本要求提供该API),因此这个crate无法在macOS上工作。如果这个crate将来添加对命名信号量的支持,看起来它应该在macOS上工作,因为它确实提供了这一点。

依赖项

~43KB