【Rust的2种线程锁 & 阻塞 vs 挂起】

发布于:2025-02-10 ⋅ 阅读:(54) ⋅ 点赞:(0)

async_std::sync::Mutexstd::sync::Mutex 之间的主要区别在于它们如何处理线程阻塞和异步编程模型。以下是两者的关键差异:

标准库的 Mutex (std::sync::Mutex)
  1. 同步阻塞:当一个线程尝试获取 std::sync::Mutex 的锁时,如果锁已经被其他线程持有,调用线程将会被阻塞,直到锁变得可用。这意味着该线程将暂停执行,直到它获得锁。

  2. 线程安全std::sync::Mutex 是线程安全的,可以在多个线程之间共享,并确保同一时间只有一个线程能够访问受保护的数据。

  3. 非异步友好:由于它会阻塞线程,因此在异步环境中使用 std::sync::Mutex 可能会导致性能问题,因为被阻塞的线程不能继续执行其他任务,浪费了线程资源。

  4. 适用场景:适用于传统的多线程环境,特别是当你可以接受或需要线程阻塞的情况。

async-std 的 Mutex (async_std::sync::Mutex)
  1. 异步非阻塞async_std::sync::Mutex 设计为与异步/等待(async/await)模式一起工作。当一个任务尝试获取锁时,如果锁不可用,该任务不会阻塞线程,而是会被挂起(suspended),允许其他任务在同一线程上运行。一旦锁变为可用,任务就会被唤醒并继续执行。

    线程阻塞(Blocked)和线程挂起(Suspended)的主要区别在于原因和恢复机制:

    • 线程阻塞:线程因为等待某个事件(如 I/O 操作完成、锁的释放等)而暂停执行,不能立即继续运行。阻塞的线程通常会进入等待队列,直到它等待的事件发生
    • 线程挂起:线程被人为地暂停执行,但不是因为等待某个外部事件。挂起可以是由于调度器决定让其他线程运行,或者是由程序显式调用某些 API 使当前线程暂停。挂起的线程可以在任何时候由系统 或程序恢复。
  2. 线程安全:同样,async_std::sync::Mutex 也是线程安全的,可以在多个线程中共享,保证同一时间只有一个任务可以访问受保护的数据。

  3. 异步友好:它是专门为异步编程设计的,避免了因等待锁而导致的任务阻塞,使得线程可以更高效地利用起来。

  4. 适用场景:适用于异步编程环境,特别是在你使用 async-std 或者其他的异步运行时来构建高并发应用程序时。

使用
std::sync::Mutex
use std::sync::{Arc, Mutex};
use std::thread;

fn main() {
    let counter = Arc::new(Mutex::new(0));
    let mut handles = vec![];

    for _ in 0..10 {
        let counter_clone = Arc::clone(&counter);
        let handle = thread::spawn(move || {
            let mut num = counter_clone.lock().unwrap();
            *num += 1;
        });
        handles.push(handle);
    }

    for handle in handles {
        handle.join().unwrap();
    }

    println!("Final counter value: {}", *counter.lock().unwrap());
}
async_std::sync::Mutex
use async_std::sync::{Arc, Mutex};
use async_std::task;

#[async_std::main]
async fn main() {
    let counter = Arc::new(Mutex::new(0));
    let mut handles = vec![];

    for _ in 0..10 {
        let counter_clone = Arc::clone(&counter);
        let handle = task::spawn(async move {
            let mut num = counter_clone.lock().await;
            *num += 1;
        });
        handles.push(handle);
    }

    for handle in handles {
        handle.await;
    }

    println!("Final counter value: {}", *counter.lock().await);
}
总结

选择 std::sync::Mutex 还是 async_std::sync::Mutex 主要取决于你的应用是否采用了异步编程模型。如果你的应用是基于异步/等待模式构建的,并且你希望避免因锁竞争导致的任务阻塞,那么你应该选择 async_std::sync::Mutex。对于传统的多线程应用,或者当你不介意线程阻塞时,std::sync::Mutex 仍然是一个合适的选择。


网站公告

今日签到

点亮在社区的每一天
去签到