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 系统编程涵盖了:
- 文件和目录操作:安全地处理文件系统
- 进程管理:与操作系统交互
- 并发编程:线程、通道和共享状态
- 内存管理:栈、堆和智能指针
- 性能优化:零成本抽象和基准测试
- 最佳实践:错误处理和资源管理
这些技能对于开发 LeBot 的低级驱动程序和实时控制系统至关重要。
参考资源
- The Rustonomicon:https://doc.rust-lang.org/nomicon/
- tokio 异步运行时:https://tokio.rs/
- crossbeam 并发库:https://docs.rs/crossbeam/