learningOS开源操作系统社区
  • 首页
  • 训练营
  • 明星学员
  • 共建单位
  • 项目实习
  • 问答论坛
登录
    Copyright © 2024 opencamp.ai All rights reserved.
    rust基础相关:move关键字如果是转移所有权,为什么这段代码是可以编译通过的?
    kingsama2025/03/29 19:35:08提问2025/03/29 19:35:08更新
      rust基础move所有权线程
    521

    我是一个刚学rust的菜鸟,各位佬勿嫌弃,我已经尽力自己去解决了。

    use std::thread;
    /// 使用的是rustc 1.85.1 (4eb161250 2025-03-15) 版本
    /// 最后代码可以编译通过,并打印7,但是这就很奇怪了?
    fn main1() {
        let mut x = 6;
        let j = thread::spawn(move || {  //按照我的理解,move发生了所有权转移,此时x应该由main线程转移到了这里。
            x = x * 2;
            thread::spawn(move || {  //move发生所有权转移,此时x由外一层的线程转移到这里一层的线程
                x = x * 2;
            })
        });
        x = x + 1;   //为什么这里main线程还可以继续访问x的值
        j.join().unwrap().join().unwrap();  //main线程阻塞等待结果,x转移到内部线程之后,并没有说明内部线程有将x的所有权移交还给main线程
        println!("{}", x);  //main线程 结果这里还是能打印x的值。
    }
    // 我的一些思考:
    // 我不太清楚rust是否会存在指令重排的问题,不过java是有的,从这点出发考虑,
    // 编译器让main线程先进行+1打印后再移交所有权给子线程。不过这里main线程有进行等待子线程,
    // 如果发生指令重排,我觉得编译器应该不会将println提前到j.join()之前,因为这会破坏语义。
    
    // 寻求大语言模型的帮助:
    // 令我感到沮丧的是,gpt等一众模型对这段代码的判断都是无法编译通过,这是和事实相矛盾的,
    // 在我向模型纠正这一点后,语言模型指出是因为x的是类型i32;其实现了copy trait。
    // 因此move行为实际上是进行了copy而非所有权转移。于是我设计一个可能不是很完美的实验。
    // 其实验的目标是:观察未实现copy trait的结构,在move中的行为是所有权转移还是copy
    
    #[derive(Debug)]
    // 一个自定义struct,它没有实现copy trait
    struct MyStruct {
        val: i32,
        msg: String,
    }
    
    fn main(){
        let mut x = MyStruct{val: 6, msg: "main线程中的值:".to_string()};
        let j = thread::spawn(move || {
            x.val=x.val*2;
            x.msg="外线程中的值:".to_string();
            println!("{}{}", x.msg,x.val);
            thread::spawn(move || {
                x.val=x.val*2;
                x.msg="里线程中的值:".to_string();
                println!("{}{}", x.msg,x.val);
            })
        });
        x.val=x.val*2;
        x.msg="main线程中修改后的值:".to_string();  //  todo
        j.join().unwrap().join().unwrap();
        println!("{}{}", x.msg,x.val);
        println!("{:?}", x);
    }
    
    // 以上这段代码依旧可以编译通过,我觉得可以说明gpt的解释是有误差的。
    // 因此我依旧没能理解为什么可以编译通过,而且更令我感到困惑的:删除todo处
    // 这一行代码,编译竟然不通过?因为rust语言给我的刻板影响是:如果你做了越多的事,
    // 被编译器驳回的概率就越大,而此时todo处,删除后,它报错了?有点颠覆我的认知。
    


    还有一点疑问:有了解到rust的线程模型与操作系统线程是1:1的关系。这点和java的线程模型一致,或者说,java的线程是托付给操作系统执行的。不过java的线程启动时机是需要start(),而在rust中似乎spawn就已经创建并启动了。这里就比较疑惑了:

    1:一个线程创建和启动是一起的(因为只有一条语句),如果是条件依赖线程,rust该如何描述这种关系(我想表达的类似于实现java中CompletableFuture 或者js中的异步编程效果)

    2:rust启动的线程也是托付给操作系统完成的吗?如果是rust自己管理的,那线程的生命周期会在什么时候消亡。如果是操作系统管理的,rust能够确保资源不泄露吗,或者说rust彻底丧失了对线程管理的控制权吗?


    回答(4)
    即可发布评论
      推荐问答
        Simple Empty
        暂无数据