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

多线程下Unsafe Rust操作Vec指针崩溃问题求助

多线程下Unsafe Rust操作Vec指针的崩溃问题

我正在学习理解Unsafe Rust在线程执行中的行为,编写了如下代码:

use std::sync::Arc;
use std::sync::atomic::{AtomicPtr, Ordering};
use std::thread;

fn main() {

    let mut arr = vec![1,2,3];
    let ptr = &mut arr as *mut Vec<i32>;
    println!("ptr : {:?}",ptr);
    // unsafe { (*ptr)[0] = 2; }
    let ptr_ref_1 = Arc::new(AtomicPtr::new(ptr));
    let a = thread::spawn(move || unsafe {
        let ptr_inner = (ptr_ref_1).load(Ordering::SeqCst);
        println!("ptr_inner_1 {:?}",ptr_inner);
        (*ptr_inner).push(4);
        println!("4 is done");
    });
    let ptr_ref_2 = Arc::new(AtomicPtr::new(ptr));
    let b = thread::spawn(move || unsafe {
        let ptr_inner = (ptr_ref_2).load(Ordering::SeqCst);
        println!("ptr_inner_2 {:?}",ptr_inner);

        (*ptr_inner).push(5);
        println!("5 is done");
    });
    let ptr_ref_3 = Arc::new(AtomicPtr::new(ptr));
    let c = thread::spawn(move || unsafe {
        // Read value
        // println!("{:?}",*(ptr_ref_3.load(Ordering::SeqCst)));
        let ptr_inner = (ptr_ref_3).load(Ordering::SeqCst);
        println!("ptr_inner_3 {:?}",ptr_inner);

        (*ptr_inner).push(6);
        println!("6 is done");
    });
    a.join().unwrap();
    b.join().unwrap();
    c.join().unwrap();
    println!("final values {:?}",arr);
}

这段代码尝试通过多个线程使用Unsafe Rust和AtomicPtr操作同一个Vec指针,95%的运行情况正常,但有5%的运行会抛出如下错误:

Output : 

ptr : 0x16d65f008
ptr_inner_1 0x16d65f008
ptr_inner_2 0x16d65f008
5 is done
main(75339,0x16d867000) malloc: pointer 0x6000022a8010 being reallocated was not allocated
main(75339,0x16d867000) malloc: *** set a breakpoint in malloc_error_break to debug
Signal: SIGABRT (signal SIGABRT)

我了解如何使用Arc/Mutex在多线程中更新值,但不清楚这段Unsafe Rust代码的错误所在,希望有人能解释问题出在哪里。


问题根源

这段代码的核心问题在于多线程无同步地调用Vec::push违反了线程安全规则,触发了内存分配器的冲突:

  • Vec并非线程安全类型,它内部包含堆内存指针、长度、容量三个字段。当push遇到容量不足时,会执行重分配:释放旧堆内存、分配新内存、拷贝数据,最后更新内部的指针、容量字段。这些操作都不是原子的,也没有任何同步机制。
  • 当多个线程并发执行push时,极有可能出现以下致命场景:
    1. 线程A检测到容量不足,启动重分配流程,已经释放了旧堆内存,但还没完成新内存分配和内部字段更新。
    2. 线程B此时也检测到容量不足,拿着已经被释放的旧堆指针去执行重分配/释放操作,直接触发malloc的错误——操作了一块已经不属于当前进程的内存。
  • AtomicPtr仅保证了指针本身的原子加载,但完全没有保护Vec内部状态的并发访问,多线程同时修改Vec的内部字段会导致数据竞争,彻底破坏Vec的结构。

为什么大部分时候能正常运行?

这是线程调度随机性导致的:如果三个线程的push操作刚好串行执行,或者重分配没有在并发时触发,就不会出现冲突;但一旦重分配发生在多线程并发执行阶段,内存错误就会触发。

正确的做法

你已经知道的Arc<Mutex<Vec<i32>>>是标准的解决方案:

  • Mutex保证同一时间只有一个线程能访问内部的Vec,彻底避免了并发修改带来的数据竞争和内存错误。
  • Arc提供了线程间共享所有权的能力,让多个线程能安全持有同一个Vec的引用。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 17:02:38