xwrust::xwos::lock

Module mtx

source
Expand description

§XWOS RUST:互斥锁

互斥锁是用来保证不同线程正确访问共享数据的机制。访问共享数据的代码片段被称为临界区。

互斥锁 只能 用在 线程上下文(Thread Context) 。等待互斥锁的线程会被阻塞,并让出CPU的使用权。

XWOS RUST框架的互斥锁是仿造 std::sync::Mutex 的来编写的。

互斥锁上锁后,可返回一个 守卫 MutexGuard ,用于提供 Scoped Lock 机制:即只负责上锁,不用关心解锁。 解锁会由 MutexGuard 在其生命周期结束后自动触发。

§创建

XWOS RUST的互斥锁可使用 Mutex::new() 创建。

  • 可以创建具有静态生命周期 static 约束的全局变量:
use xwrust::xwos::lock::mtx::*;

static GLOBAL_MUTEX: Mutex<u32> = Mutex::new(0);
extern crate alloc;
use alloc::sync::Arc;

use xwrust::xwos::lock::mtx::*;

pub fn xwrust_example_mutex() {
    let mutex: Arc<Mutex<u32>> = Arc::new(Mutex::new(0));
}

§初始化

无论以何种方式创建的互斥锁,都必须在使用前调用 Mutex::init() 进行初始化:

pub fn xwrust_example_mutex() {
    GLOBAL_MUTEX.init();
    mutex.init();
}

§解锁

上锁后返回的 MutexGuardMutexGuard 的生命周期结束时,会自动解锁。 也可调用 Mutex::unlock() 主动消费掉 MutexGuard 来解锁。

§上锁

§普通等待上锁

Mutex::lock() 方法只可在 线程 上下文中使用:

  • 若线程无法获得锁,会阻塞等待。
  • 当锁的占用者解锁时,锁会唤醒优先级最高的线程,并让此线程获得锁。
  • 线程获得锁后返回 Ok() ,并在其中包含锁的守卫 MutexGuard
  • 当线程阻塞等待被中断时,会在 Err() 中返回 MutexError::Interrupt

§超时等待上锁

Mutex::lock_to() 方法只可在 线程 上下文中使用:

  • 若线程无法获得锁,会阻塞等待,等待时会指定一个唤醒时间点。
  • 当锁的占用者解锁时,锁会唤醒优先级最高的线程,并让此线程获得锁。
  • 线程获得锁后返回 Ok() ,并在其中包含锁的守卫 MutexGuard
  • 当线程阻塞等待被中断时,会在 Err() 中返回 MutexError::Interrupt
  • 当到达指定的唤醒时间点,线程被唤醒,并返回 MutexError::Timedout

§不可中断等待上锁

Mutex::lock_unintr() 方法只可在 线程 上下文中使用:

  • 若线程无法获得锁,会阻塞等待,且不可被中断,也不会超时。
  • 当锁的占用者解锁时,锁会唤醒优先级最高的线程,并让此线程获得锁。
  • 线程获得锁后返回 Ok() ,并在其中包含锁的守卫 MutexGuard

§尝试等待上锁

Mutex::trylock() 方法只可在 线程 上下文中使用,不会阻塞线程,只会检测锁是否可被获取:

§示例

XWOS/xwam/xwrust-example/xwrust_example_mutex

§对比 std::sync::Mutex

  • XWOS RUST
use xwrust::xwos::thd;
use xwrust::xwos::lock::mtx::*;
extern crate alloc;
use alloc::sync::Arc;

pub fn xwrust_example_mutex() {
    // ...省略...
    let lock: Arc<Mutex<u32>> = Arc::new(Mutex::new(0));
    let lock_child = lock.clone();

    match lock.lock() {
        Ok(mut guard) => { // 主线程上锁成功
            *guard = 1; // 访问共享变量
        }
        Err(e) => {
            // 主线程上锁失败
        }
    }
    // ...省略...
    thd::Builder::new()
        .name("child".into())
        .spawn(move |_| {
            // 子线程闭包
            match lock_child.lock() {
                Ok(mut guard) => { // 子线程上锁成功
                    *guard += 1;
                }
                Err(e) => { // 子线程上锁失败
                }
            }
        });
}
use std::sync::{Arc, Mutex};
use std::thread;

fn main() {
    // 创建互斥锁的方法类似
    let lock = Arc::new(Mutex::new(0_u32));
    let lock2 = Arc::clone(&lock);

    let _ = thread::spawn(move || -> () {
        // 访问共享数据的方法类似:
        // 子线程中对互斥锁上锁, unwrap() 从 Ok() 中取出 guard,再对 guard 解可变引用可得数据的可变引用
        let guard = lock2.lock().unwrap();
        *guard = 1;

        // std库特有的机制:持有锁时 panic!() 将导致锁变成 **中毒状态(poisoned)** 。
        panic!();
    }).join();

    // std库特有的机制:处理中毒状态的锁
    let mut guard = match lock.lock() {
        Ok(guard) => guard,
        Err(poisoned) => poisoned.into_inner(),
    };
    *guard += 1;
}

§构建全局变量的方式

§中毒锁机制

  • std::sync::Mutex 提供了 Poisoned Mutex 机制。 当通过 std::thread::spawn() 创建的子线程在持有 互斥锁 时,发生了 panic!() , 此时 互斥锁 的状态被称为 中毒(Poisoned)std::sync::Mutex 可在父线程中检测到此错误状态,并尝试恢复。
  • xwrust::xwos::lock::mtx 不提供此机制,用户必须处理 Ok()Err() ,不可使用 unwrap()。 因为此机制需要依赖 unwind 机制 ,目前 unwind 在MCU上还不成熟:
    • Gcc可以在MCU C++中使用 try-catch
    • LLVM(Clan++)还无法支持在MCU C++中使用 try-catch
    • Rust目前在MCU上还无法使用 panic_unwind 的 feature。

Structs§

Enums§

Constants§