Skip to content

Rust 系统编程

引言

在上一章中,我们学习了 Rust 的基础知识。现在我们将深入探讨系统编程,这对于 LeBot 的底层控制至关重要。系统编程涉及与操作系统、硬件和资源的直接交互。我们将学习如何处理文件 I/O、进程管理、并发编程和性能优化。

文件 I/O

基础文件操作

rust
use std::fs;
use std::fs::File;
use std::io::{self, Read, Write, BufRead, BufReader};

// 读取整个文件
fn read_entire_file(path: &str) -> io::Result<String> {
    fs::read_to_string(path)
}

// 写入文件
fn write_file(path: &str, content: &str) -> io::Result<()> {
    fs::write(path, content)
}

// 追加文件
fn append_to_file(path: &str, content: &str) -> io::Result<()> {
    let mut file = fs::OpenOptions::new()
        .create(true)
        .append(true)
        .open(path)?;
    
    file.write_all(content.as_bytes())?;
    Ok(())
}

// 逐行读取文件
fn read_lines(path: &str) -> io::Result<()> {
    let file = File::open(path)?;
    let reader = BufReader::new(file);
    
    for line in reader.lines() {
        let line = line?;
        println!("{}", line);
    }
    
    Ok(())
}

// 读取二进制文件
fn read_binary_file(path: &str) -> io::Result<Vec<u8>> {
    fs::read(path)
}

fn main() {
    // 写入文件
    if let Err(e) = write_file("robot_config.txt", "Motor count: 4\nBattery: 100%") {
        eprintln!("Failed to write file: {}", e);
        return;
    }
    
    // 读取整个文件
    match read_entire_file("robot_config.txt") {
        Ok(content) => println!("File content:\n{}", content),
        Err(e) => eprintln!("Failed to read file: {}", e),
    }
    
    // 追加到文件
    if let Err(e) = append_to_file("robot_config.txt", "\nVersion: 1.0") {
        eprintln!("Failed to append to file: {}", e);
    }
    
    // 逐行读取
    if let Err(e) = read_lines("robot_config.txt") {
        eprintln!("Failed to read lines: {}", e);
    }
}

目录操作

rust
use std::fs;
use std::path::Path;

// 列出目录中的文件
fn list_directory(path: &str) -> std::io::Result<()> {
    for entry in fs::read_dir(path)? {
        let entry = entry?;
        let path = entry.path();
        
        if path.is_dir() {
            println!("Dir:  {}", path.display());
        } else {
            println!("File: {}", path.display());
        }
    }
    
    Ok(())
}

// 创建目录
fn create_directory(path: &str) -> std::io::Result<()> {
    fs::create_dir_all(path)?;
    println!("Created directory: {}", path);
    Ok(())
}

// 删除文件
fn delete_file(path: &str) -> std::io::Result<()> {
    fs::remove_file(path)?;
    println!("Deleted file: {}", path);
    Ok(())
}

// 删除目录
fn delete_directory(path: &str) -> std::io::Result<()> {
    fs::remove_dir_all(path)?;
    println!("Deleted directory: {}", path);
    Ok(())
}

// 获取文件元数据
fn get_file_info(path: &str) -> std::io::Result<()> {
    let metadata = fs::metadata(path)?;
    
    println!("File: {}", path);
    println!("Size: {} bytes", metadata.len());
    println!("Is directory: {}", metadata.is_dir());
    println!("Is file: {}", metadata.is_file());
    
    if let Ok(modified) = metadata.modified() {
        println!("Last modified: {:?}", modified);
    }
    
    Ok(())
}

fn main() {
    // 创建目录
    let _ = create_directory("robot_logs");
    
    // 列出目录
    if let Err(e) = list_directory(".") {
        eprintln!("Failed to list directory: {}", e);
    }
    
    // 获取文件信息
    if let Err(e) = get_file_info("robot_config.txt") {
        eprintln!("Failed to get file info: {}", e);
    }
}

进程和系统调用

rust
use std::process::{Command, Stdio};
use std::io::Write;

// 执行外部命令
fn run_command(cmd: &str, args: &[&str]) -> std::io::Result<String> {
    let output = Command::new(cmd)
        .args(args)
        .output()?;
    
    let stdout = String::from_utf8_lossy(&output.stdout);
    let stderr = String::from_utf8_lossy(&output.stderr);
    
    if !output.status.success() {
        eprintln!("Command failed: {}", stderr);
    }
    
    Ok(stdout.to_string())
}

// 与子进程通信
fn run_interactive_command(cmd: &str) -> std::io::Result<()> {
    let mut child = Command::new(cmd)
        .stdin(Stdio::piped())
        .stdout(Stdio::piped())
        .spawn()?;
    
    // 获取 stdin
    if let Some(mut stdin) = child.stdin.take() {
        stdin.write_all(b"input data\n")?;
    }
    
    // 等待完成
    let status = child.wait()?;
    println!("Process exited with status: {}", status);
    
    Ok(())
}

// 获取系统信息
fn get_system_info() {
    // 获取 CPU 数量
    let num_cpus = num_cpus::get();
    println!("Number of CPUs: {}", num_cpus);
    
    // 使用 sys-info crate 获取更多信息
    // (需要添加依赖)
}

fn main() {
    // 运行简单命令
    match run_command("echo", &["Hello from LeBot"]) {
        Ok(output) => println!("Output: {}", output),
        Err(e) => eprintln!("Failed to run command: {}", e),
    }
    
    // 查看 CPU 数量
    get_system_info();
}

并发编程

线程

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

// 基础线程
fn basic_threading() {
    let thread1 = thread::spawn(|| {
        for i in 1..=5 {
            println!("Thread 1: {}", i);
            thread::sleep(Duration::from_millis(100));
        }
    });
    
    let thread2 = thread::spawn(|| {
        for i in 1..=5 {
            println!("Thread 2: {}", i);
            thread::sleep(Duration::from_millis(100));
        }
    });
    
    // 等待线程完成
    thread1.join().unwrap();
    thread2.join().unwrap();
    
    println!("All threads completed");
}

// 共享状态
fn shared_state() {
    let counter = Arc::new(Mutex::new(0));
    let mut handles = vec![];
    
    for i in 0..10 {
        let counter_clone = Arc::clone(&counter);
        
        let handle = thread::spawn(move || {
            let mut num = counter_clone.lock().unwrap();
            *num += 1;
            println!("Thread {}: counter = {}", i, *num);
        });
        
        handles.push(handle);
    }
    
    for handle in handles {
        handle.join().unwrap();
    }
    
    println!("Final counter: {}", *counter.lock().unwrap());
}

// 电机控制线程
struct Motor {
    id: u32,
    speed: Arc<Mutex<i32>>,
}

impl Motor {
    fn new(id: u32) -> Self {
        Motor {
            id,
            speed: Arc::new(Mutex::new(0)),
        }
    }
    
    fn set_speed(&self, speed: i32) {
        if let Ok(mut s) = self.speed.lock() {
            *s = speed;
        }
    }
    
    fn get_speed(&self) -> i32 {
        if let Ok(s) = self.speed.lock() {
            *s
        } else {
            0
        }
    }
    
    fn start_control_loop(&self) {
        let speed_clone = Arc::clone(&self.speed);
        let motor_id = self.id;
        
        thread::spawn(move || {
            for _ in 0..10 {
                if let Ok(s) = speed_clone.lock() {
                    println!("Motor {} current speed: {}", motor_id, *s);
                }
                thread::sleep(Duration::from_millis(100));
            }
        });
    }
}

fn main() {
    println!("=== Basic Threading ===");
    basic_threading();
    
    println!("\n=== Shared State ===");
    shared_state();
    
    println!("\n=== Motor Control ===");
    let motor = Motor::new(0);
    motor.start_control_loop();
    
    for speed in [100, 200, 300, 200, 100, 0].iter() {
        motor.set_speed(*speed);
        thread::sleep(Duration::from_millis(200));
    }
    
    thread::sleep(Duration::from_secs(2));
}

通道(Channel)

rust
use std::sync::mpsc;
use std::thread;
use std::time::Duration;

// 基础通道
fn channel_basics() {
    let (tx, rx) = mpsc::channel();
    
    thread::spawn(move || {
        let messages = vec!["command 1", "command 2", "command 3"];
        
        for msg in messages {
            tx.send(msg).unwrap();
            thread::sleep(Duration::from_secs(1));
        }
    });
    
    while let Ok(msg) = rx.recv() {
        println!("Received: {}", msg);
    }
}

// 多发送者
fn multiple_senders() {
    let (tx, rx) = mpsc::channel();
    let mut handles = vec![];
    
    for i in 0..3 {
        let tx_clone = tx.clone();
        
        let handle = thread::spawn(move || {
            for j in 0..2 {
                let msg = format!("Message {} from thread {}", j, i);
                tx_clone.send(msg).unwrap();
                thread::sleep(Duration::from_millis(100));
            }
        });
        
        handles.push(handle);
    }
    
    drop(tx);  // 关闭原始发送者
    
    for msg in rx {
        println!("Received: {}", msg);
    }
    
    for handle in handles {
        handle.join().unwrap();
    }
}

// 机器人命令通道
#[derive(Debug, Clone)]
enum RobotCommand {
    Move(i32),
    Stop,
    Shutdown,
}

fn robot_with_channels() {
    let (tx, rx) = mpsc::channel();
    
    // 机器人控制线程
    thread::spawn(move || {
        loop {
            match rx.recv() {
                Ok(RobotCommand::Move(speed)) => {
                    println!("Moving at speed: {}", speed);
                }
                Ok(RobotCommand::Stop) => {
                    println!("Stopping robot");
                }
                Ok(RobotCommand::Shutdown) => {
                    println!("Shutting down");
                    break;
                }
                Err(_) => break,
            }
        }
    });
    
    // 发送命令
    tx.send(RobotCommand::Move(100)).unwrap();
    thread::sleep(Duration::from_millis(500));
    
    tx.send(RobotCommand::Move(200)).unwrap();
    thread::sleep(Duration::from_millis(500));
    
    tx.send(RobotCommand::Stop).unwrap();
    thread::sleep(Duration::from_millis(500));
    
    tx.send(RobotCommand::Shutdown).unwrap();
    thread::sleep(Duration::from_secs(1));
}

fn main() {
    println!("=== Channel Basics ===");
    channel_basics();
    
    println!("\n=== Multiple Senders ===");
    multiple_senders();
    
    println!("\n=== Robot Commands ===");
    robot_with_channels();
}

内存管理

栈和堆

rust
// 栈分配(大小必须在编译时已知)
fn stack_allocation() {
    let x: i32 = 5;              // 栈上分配 4 字节
    let arr: [i32; 5] = [1, 2, 3, 4, 5];  // 栈上分配 20 字节
    
    println!("x = {}", x);
    println!("arr = {:?}", arr);
}

// 堆分配
fn heap_allocation() {
    let v: Vec<i32> = vec![1, 2, 3, 4, 5];  // 指针在栈,数据在堆
    let s: String = String::from("hello");   // 指针在栈,字符串在堆
    
    println!("Vector: {:?}", v);
    println!("String: {}", s);
}

// 智能指针
fn smart_pointers() {
    use std::rc::Rc;
    use std::sync::Arc;
    
    // Rc:引用计数(单线程)
    let data = Rc::new(vec![1, 2, 3, 4, 5]);
    let ptr1 = Rc::clone(&data);
    let ptr2 = Rc::clone(&data);
    
    println!("Reference count: {}", Rc::strong_count(&data));
    
    // Arc:原子引用计数(多线程)
    let shared_data = Arc::new(vec![10, 20, 30]);
    let shared_clone = Arc::clone(&shared_data);
    
    std::thread::spawn(move || {
        println!("Thread data: {:?}", shared_clone);
    });
    
    println!("Main thread data: {:?}", shared_data);
}

fn main() {
    stack_allocation();
    println!();
    heap_allocation();
    println!();
    smart_pointers();
}

内存安全

rust
// 避免缓冲区溢出
fn safe_array_access() {
    let arr = [1, 2, 3, 4, 5];
    
    // 安全的方式
    if let Some(element) = arr.get(10) {
        println!("Element: {}", element);
    } else {
        println!("Index out of bounds");
    }
    
    // 使用迭代器
    for (i, &element) in arr.iter().enumerate() {
        println!("arr[{}] = {}", i, element);
    }
}

// 避免悬空指针
fn no_dangling_pointers() {
    let s: String;
    {
        let s_inner = String::from("hello");
        s = s_inner;  // s_inner 的所有权转移给 s
    }
    // s 仍然有效,因为它拥有字符串
    println!("s = {}", s);
}

// 避免双重释放
fn no_double_free() {
    let v1 = vec![1, 2, 3];
    let v2 = v1;  // v1 的所有权转移给 v2
    // println!("{:?}", v1);  // 编译错误:v1 已无效
    println!("{:?}", v2);     // 正确
}

fn main() {
    safe_array_access();
    println!();
    no_dangling_pointers();
    println!();
    no_double_free();
}

性能优化

零成本抽象

rust
// 编译时优化:泛型单态化
fn generic_function<T: std::ops::Add<Output=T>>(a: T, b: T) -> T {
    a + b
}

fn main() {
    // 编译器为 i32 和 f64 生成不同的代码
    let sum_int = generic_function(5i32, 3i32);
    let sum_float = generic_function(5.0f64, 3.0f64);
    
    println!("int: {}, float: {}", sum_int, sum_float);
}

// 内联优化
#[inline]
fn add(a: i32, b: i32) -> i32 {
    a + b
}

#[inline(never)]
fn multiply(a: i32, b: i32) -> i32 {
    a * b
}

fn main() {
    let result = add(5, 3);
    println!("5 + 3 = {}", result);
}

性能测试

rust
// 使用标准库的 time
use std::time::Instant;

fn performance_test() {
    let start = Instant::now();
    
    // 执行某些操作
    let mut sum = 0;
    for i in 0..1_000_000 {
        sum += i;
    }
    
    let duration = start.elapsed();
    
    println!("Sum: {}", sum);
    println!("Time: {:?}", duration);
}

fn main() {
    performance_test();
}

系统编程最佳实践

错误处理

rust
use std::io;
use std::fs;

// 定义自己的错误类型
#[derive(Debug)]
enum RobotSystemError {
    IoError(io::Error),
    ConfigError(String),
    HardwareError(String),
}

impl From<io::Error> for RobotSystemError {
    fn from(err: io::Error) -> Self {
        RobotSystemError::IoError(err)
    }
}

// 结果类型别名
type RobotResult<T> = Result<T, RobotSystemError>;

// 使用自定义错误
fn initialize_robot(config_path: &str) -> RobotResult<()> {
    let config = fs::read_to_string(config_path)?;
    
    if config.is_empty() {
        return Err(RobotSystemError::ConfigError("Empty config".to_string()));
    }
    
    Ok(())
}

fn main() {
    match initialize_robot("robot.conf") {
        Ok(_) => println!("Robot initialized successfully"),
        Err(e) => eprintln!("Error: {:?}", e),
    }
}

资源管理

rust
// RAII 模式:获取即初始化
struct Resource {
    id: u32,
}

impl Resource {
    fn new(id: u32) -> Self {
        println!("Acquiring resource {}", id);
        Resource { id }
    }
}

impl Drop for Resource {
    fn drop(&mut self) {
        println!("Releasing resource {}", self.id);
    }
}

fn use_resource() {
    let _r1 = Resource::new(1);
    let _r2 = Resource::new(2);
    // 作用域结束时自动释放资源
}

fn main() {
    use_resource();
    println!("All resources released");
}

总结

Rust 系统编程涵盖了:

  1. 文件和目录操作:安全地处理文件系统
  2. 进程管理:与操作系统交互
  3. 并发编程:线程、通道和共享状态
  4. 内存管理:栈、堆和智能指针
  5. 性能优化:零成本抽象和基准测试
  6. 最佳实践:错误处理和资源管理

这些技能对于开发 LeBot 的低级驱动程序和实时控制系统至关重要。


参考资源

由 LeBot 开发团队编写