Rust轻量级互斥锁库simple-mutex的使用,高效线程安全同步原语解决方案

Rust轻量级互斥锁库simple-mutex的使用,高效线程安全同步原语解决方案

simple-mutex简介

一个简单的互斥锁实现。比std::sync::Mutex更高效,比parking_lot::Mutex更简单。

该锁机制使用最终公平性来确保锁在平均情况下是公平的,而不会牺牲性能。这是通过在锁操作被饥饿超过0.5毫秒时强制公平锁来实现的。

示例代码

以下是一个基础使用示例,展示了如何在多线程环境下安全地递增一个计数器:

use simple_mutex::Mutex;
use std::sync::Arc;
use std::thread;

let m = Arc::new(Mutex::new(0));
let mut threads = vec![];

for _ in 0..10 {
    let m = m.clone();
    threads.push(thread::spawn(move || {
        *m.lock() += 1;
    }));
}

for t in threads {
    t.join().unwrap();
}
assert_eq!(*m.lock(), 10);

完整示例demo

以下是一个更完整的示例,展示了如何在多线程环境下使用simple-mutex进行更复杂的数据共享:

use simple_mutex::Mutex;
use std::sync::Arc;
use std::thread;
use std::time::Duration;

// 共享数据结构
struct SharedData {
    counter: Mutex<i32>,      // 计数器
    logs: Mutex<Vec<String>>, // 日志记录
}

fn main() {
    // 创建共享数据
    let shared_data = Arc::new(SharedData {
        counter: Mutex::new(0),
        logs: Mutex::new(Vec::new()),
    });

    let mut handles = vec![];

    // 创建5个工作线程
    for i in 0..5 {
        let data = shared_data.clone();
        handles.push(thread::spawn(move || {
            // 获取计数器锁并递增
            let mut counter = data.counter.lock();
            *counter += 1;
            
            // 模拟一些处理时间
            thread::sleep(Duration::from_millis(100));
            
            // 获取日志锁并添加条目
            let mut logs = data.logs.lock();
            logs.push(format!("Thread {} incremented counter to {}", i, *counter));
        }));
    }

    // 等待所有线程完成
    for handle in handles {
        handle.join().unwrap();
    }

    // 打印最终结果
    let counter = shared_data.counter.lock();
    let logs = shared_data.logs.lock();
    
    println!("Final counter value: {}", *counter);
    println!("Log entries:");
    for log in logs.iter() {
        println!("- {}", log);
    }
}

安装

在项目目录中运行以下Cargo命令:

cargo add simple-mutex

或者在Cargo.toml中添加以下行:

simple-mutex = "1.1.5"

许可证

该库采用以下任一许可证:

  • Apache License, Version 2.0
  • MIT license

特点

  1. 轻量级: 比标准库的Mutex实现更高效
  2. 简单易用: 接口简洁,学习成本低
  3. 最终公平性: 通过饥饿检测机制确保长期公平性
  4. 线程安全: 提供可靠的线程同步原语

simple-mutex特别适合需要轻量级同步原语的场景,特别是在性能敏感的应用中。它提供了一种简单而有效的方式来保护共享数据免受并发访问的影响。


1 回复

Rust轻量级互斥锁库simple-mutex的使用

简介

simple-mutex是一个Rust语言的轻量级互斥锁(Mutex)实现库,提供了高效的线程安全同步原语解决方案。相比标准库的std::sync::Mutex,它在某些场景下具有更小的开销和更高的性能。

特点

  • 轻量级实现,减少不必要的开销
  • 无依赖,纯Rust实现
  • 适用于需要高性能锁的场景
  • 简单的API设计,易于使用

使用方法

添加依赖

首先在Cargo.toml中添加依赖:

[dependencies]
simple-mutex = "0.2"

基本使用

use simple_mutex::Mutex;
use std::sync::Arc;
use std::thread;

fn main() {
    // 创建一个被Mutex保护的共享数据
    let counter = Arc::new(Mutex::new(0));
    
    let mut handles = vec![];

    for _ in 0..10 {
        let counter = Arc::clone(&counter);
        let handle = thread::spawn(move || {
            // 获取锁
            let mut num = counter.lock();
            
            // 修改共享数据
            *num += 1;
            
            // 锁会在离开作用域时自动释放
        });
        handles.push(handle);
    }

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

    println!("最终结果: {}", *counter.lock());
}

与标准库Mutex的对比

use simple_mutex::Mutex as SimpleMutex;
use std::sync::Mutex as StdMutex;
use std::time::Instant;

fn benchmark() {
    let simple_mutex = SimpleMutex::new(0);
    let std_mutex = StdMutex::new(0);
    
    let start = Instant::now();
    for _ in 0..1_000_000 {
        *simple_mutex.lock() += 1;
    }
    let simple_duration = start.elapsed();
    
    let start = Instant::now();
    for _ in 0..1_000_000 {
        *std_mutex.lock().unwrap() += 1;
    }
    let std_duration = start.elapsed();
    
    println!("simple-mutex用时: {:?}", simple_duration);
    println!("std::sync::Mutex用时: {:?}", std_duration);
}

高级用法:条件变量配合使用

虽然simple-mutex本身不提供条件变量,但可以与标准库的条件变量配合使用:

use simple_mutex::Mutex;
use std::sync::{Arc, Condvar};
use std::thread;

fn main() {
    let pair = Arc::new((Mutex::new(false), Condvar::new()));
    let pair2 = Arc::clone(&pair);

    thread::spawn(move || {
        let (lock, cvar) = &*pair2;
        let mut started = lock.lock();
        *started = true;
        cvar.notify_one();
    });

    let (lock, cvar) = &*pair;
    let mut started = lock.lock();
    while !*started {
        started = cvar.wait(started);
    }
    
    println!("条件已满足");
}

完整示例demo

下面是一个结合simple-mutex和线程池的完整示例:

use simple_mutex::Mutex;
use std::sync::Arc;
use std::thread;
use std::time::Duration;

// 共享数据结构
struct SharedData {
    counter: Mutex<i32>,
    log: Mutex<Vec<String>>,
}

fn main() {
    // 创建共享数据
    let shared_data = Arc::new(SharedData {
        counter: Mutex::new(0),
        log: Mutex::new(Vec::new()),
    });

    let mut handles = vec![];

    // 创建5个工作线程
    for i in 0..5 {
        let data = Arc::clone(&shared_data);
        let handle = thread::spawn(move || {
            // 模拟工作
            thread::sleep(Duration::from_millis(100));
            
            // 修改计数器
            {
                let mut counter = data.counter.lock();
                *counter += 1;
            }
            
            // 添加日志
            {
                let mut log = data.log.lock();
                log.push(format!("线程 {} 完成了工作", i));
            }
        });
        handles.push(handle);
    }

    // 等待所有线程完成
    for handle in handles {
        handle.join().unwrap();
    }

    // 打印最终结果
    println!("最终计数器值: {}", *shared_data.counter.lock());
    println!("日志记录:");
    for entry in shared_data.log.lock().iter() {
        println!("- {}", entry);
    }
}

适用场景

  1. 高频率的锁操作
  2. 临界区代码执行时间短的场景
  3. 需要最小化同步开销的应用程序
  4. 嵌入式或资源受限环境

注意事项

  • 不提供毒锁(poisoning)处理机制
  • 对于长时间持有的锁,标准库的Mutex可能更合适
  • 在锁竞争激烈的情况下,性能优势可能不明显

simple-mutex为Rust开发者提供了一个简单高效的同步原语选择,特别适合那些对性能敏感的应用程序。

回到顶部