4 个版本
0.2.0 | 2021 年 10 月 12 日 |
---|---|
0.1.2 | 2021 年 10 月 6 日 |
0.1.1 | 2021 年 10 月 6 日 |
0.1.0 | 2021 年 10 月 6 日 |
#482 in 并发
每月 22 次下载
用于 linux-rtic
19KB
261 行(不含注释)
pcp-mutex
基于 Linux PI futex 的优先级上限协议(PCP)互斥锁。允许高效且无死锁的执行。
工作原理
Linux 内核不支持优先级上限协议(PCP),这对于实时系统来说至关重要,既能保证良好的可调度性,又能确保无死锁执行。该包使用优先级继承(PI)futex 模拟原始优先级上限协议(OPCP)。
在内部,每个 PcpMutex
都属于某个 PcpGroup
,该组包含对最高锁持有者的原子指针。任何尝试锁定 PcpMutex
的操作首先会与这个最高锁持有者进行比较,如果满足 PCP 锁定条件,则会成功。futex 通过涉及零系统调用的原子操作进行锁定。如果失败,当前线程将在最高锁持有者上调用 futex LOCK_PI
系统调用,内核将提高锁持有者的优先级。
默认情况下,PcpMutex::new()
使用默认的全局组。程序的不同部分可以使用多个组进行隔离。
这在与 POSIX PTHREAD_PRIO_PROTECT
互斥锁的两个方面不同
- POSIX 互斥锁在每次锁定/解锁时都会调用
sched_setparam
系统调用,这要慢得多。该库仅在快速路径上使用原子操作。 - POSIX 互斥锁是独立的(没有系统上限)并且不能防止死锁。它不是一个“真正的”PCP。
每个线程还持有内部线程局部 ThreadState
对象,该对象包含线程 id(来自 gettid
系统调用)和优先级(来自 sched_getparam
),用于内部逻辑。如果线程优先级被手动更改(即 sched_setparam
系统调用),则必须调用 thread::update_priority()
来更新内部状态。对于实时应用程序,有一个便利函数 thread::init_fifo_priority(priority: u8)
,它将调度策略设置为 SCHED_FIFO
并给定优先级,同时更新内部状态。在持有互斥锁时避免更改线程优先级,因为这可能导致死锁。
示例
以不同的顺序锁定 2 个互斥锁会导致死锁,但 PCP 可以防止这种情况
let a = Arc::new(PcpMutex::new(0, 3));
let b = Arc::new(PcpMutex::new(0, 3));
{
let a = a.clone();
let b = b.clone();
thread::spawn(move || {
println!("Thread 1 tries a lock");
a.lock(|a| {
println!("Thread 1 holds a lock");
*a += 1;
thread::sleep(std::time::Duration::from_millis(100));
println!("Thread 1 tries b lock");
b.lock(|b| {
println!("Thread 1 holds b lock");
*b += 1;
});
println!("Thread 1 released b lock");
});
println!("Thread 1 released a lock");
});
}
{
let a = a.clone();
let b = b.clone();
thread::spawn(move || {
println!("Thread 2 tries b lock");
b.lock(|b| {
println!("Thread 2 holds b lock");
*b += 1;
thread::sleep(std::time::Duration::from_millis(100));
println!("Thread 2 tries a lock");
a.lock(|a| {
println!("Thread 2 holds a lock");
*a += 1;
});
println!("Thread 2 released a lock");
});
println!("Thread 2 released b lock");
});
}
输出
Thread 1 tries a lock
Thread 1 holds a lock
Thread 2 tries b lock <--- thread 2 is prevented from taking a lock here by PCP
Thread 1 tries b lock
Thread 1 holds b lock
Thread 1 released b lock
Thread 1 released a lock
Thread 2 holds b lock
Thread 2 tries a lock
Thread 2 holds a lock
Thread 2 released a lock
Thread 2 released b lock
鸣谢
这项工作是我于屯特大学论文的一部分。
依赖关系
~80KB