You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rust多线程股票模拟问题:股票值无法一致更新求解

多线程股票交易所模拟的正确实现思路与代码修正

核心问题分析

你之前的两种方案都存在根本性缺陷:

  1. 可变引用传递方案:Arc<Mutex<&mut [Stock]>> 违反了Rust的生命周期规则,可变引用无法脱离原始所有者的生命周期进行跨线程传递,必然导致编译错误。
  2. 克隆对象传递方案:生成器每次发送的是原始股票的克隆副本,增量器修改的只是副本而非共享状态,生成器后续又会发送原始状态的克隆,最终导致广播器收到新旧混杂的数据,出现价格回退的现象。

正确实现思路

采用共享唯一状态+消息触发更新的模式,核心规则:

  • 用Arc<Mutex<Vec<Stock>>>维护唯一的股票状态,所有线程共享该状态,但仅允许增量器持有锁时修改状态。
  • 生成器不直接传递股票对象,仅发送「需要更新的股票索引」给增量器,触发更新操作。
  • 增量器接收索引后,锁定共享状态完成价格修改,再将修改后的股票克隆发送给广播器。
  • 两个广播器从同一个多生产者通道接收数据,实现消息广播。

完整修正代码

依赖配置(Cargo.toml)

[dependencies]
crossbeam-channel = "0.5"
rand = "0.8"

实现代码

use crossbeam_channel::{unbounded, Receiver, Sender};
use std::sync::{Arc, Mutex};
use std::thread;
use std::time::Duration;

#[derive(Debug, Clone)]
struct Stock {
    name: String,
    price: f64,
}

fn main() {
    // 初始化共享股票状态
    let stocks = Arc::new(Mutex::new(vec![
        Stock {
            name: "Apple".to_string(),
            price: 150.0,
        },
        Stock {
            name: "Microsoft".to_string(),
            price: 107.0,
        },
    ]));

    // 创建通道:生成器 -> 增量器(传递股票索引)
    let (gen_sender, inc_receiver) = unbounded::<usize>();
    // 创建通道:增量器 -> 广播器(传递更新后的股票)
    let (inc_sender, broadcast_receiver) = unbounded::<Stock>();

    // 1. 生成器线程:循环发送股票索引,触发更新
    let gen_stocks = Arc::clone(&stocks);
    let gen_sender_clone = gen_sender.clone();
    thread::spawn(move || {
        loop {
            let stock_count = gen_stocks.lock().unwrap().len();
            for idx in 0..stock_count {
                gen_sender_clone.send(idx).unwrap();
                thread::sleep(Duration::from_millis(500)); // 控制更新频率
            }
        }
    });

    // 2. 增量器线程:接收索引,修改股票价格,发送给广播器
    let inc_stocks = Arc::clone(&stocks);
    let inc_sender_clone = inc_sender.clone();
    thread::spawn(move || {
        while let Ok(idx) = inc_receiver.recv() {
            // 锁定共享状态并修改价格
            let mut stocks_guard = inc_stocks.lock().unwrap();
            let stock = &mut stocks_guard[idx];
            // 模拟随机价格波动(±5以内)
            let price_change = (rand::random::<f64>() * 10.0) - 5.0;
            stock.price = (stock.price + price_change).max(1.0); // 防止价格为负
            let updated_stock = stock.clone();
            
            // 提前释放锁,减少锁持有时间,提升并发效率
            drop(stocks_guard);
            
            inc_sender_clone.send(updated_stock).unwrap();
        }
    });

    // 3. 两个广播器线程:接收并打印股票信息
    for broadcaster_id in 1..=2 {
        let receiver_clone = broadcast_receiver.clone();
        thread::spawn(move || {
            println!("Broadcaster {} 启动", broadcaster_id);
            while let Ok(stock) = receiver_clone.recv() {
                println!(
                    "Broadcaster {}: {} - ${:.2}",
                    broadcaster_id, stock.name, stock.price
                );
            }
        });
    }

    // 阻塞主线程,避免程序退出
    loop {
        thread::sleep(Duration::from_secs(60));
    }
}

方案优势

  1. 状态一致性:所有股票修改操作都在持有Mutex锁的情况下完成,保证了共享状态的唯一性,不会出现价格回退。
  2. 避免生命周期问题:无需传递可变引用,仅通过索引触发状态修改,完全符合Rust的安全规则。
  3. 并发效率优化:提前释放锁的操作减少了锁的持有时间,让生成器和广播器能更高效地工作。

内容的提问来源于stack exchange,提问作者AlphabetsAlphabets

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 22:12:47