相互关联的作用域如何创建“数据竞赛”?

The Rust book talks about having multiple readers and multiple mutable references to an object as a data race situation that may lead to issues.

例如,此代码:

fn main() {
    let mut x = 1;
    let r1 = &mut x;
    *r1 = 2;
    let r2 = &mut x;
    *r2 = 3;
    println!("{}", r1);
    println!("{}", r2);
}

will be rejected by Rust compiler because r1 and r2 scopes are intertwined.

但是这里有什么问题?我的意思是,这只是一个线程,没有“同时读写”,因此所有这些语句应严格按顺序执行,并提供确定性的可再现结果。

评论
  • 鸣人
    鸣人 回复

    From Niko Matsakis' blog:

    我经常认为,尽管从技术意义上讲数据争夺只能在并行系统中发生,但在顺序系统中,感觉就像数据竞赛的问题一直无休止地出现。一个示例就是C ++民间称之为迭代器失效的方法-基本上,如果您遍历哈希表并且尝试在该迭代期间修改哈希表,则会得到未定义的行为。有时您的迭代会跳过键或值,有时会向您显示新键,有时却没有,等等。      但是无论结果如何,迭代器失效感觉都与数据竞争非常相似。通常会出现此问题,因为您有一段代码在哈希表上迭代,然后调用在其他模块中定义的子例程。然后,另一个模块将写入同一哈希表。这两个模块本身看起来都不错,只是这两个模块的组合才引起问题。而且由于结果的不确定性,通常会导致代码长时间正常运行,直到不能正常运行。      Rust的类型系统可防止迭代器失效。

    Rust的类型系统不允许像这样的单线程程序进行编译,因为它们会导致未定义的行为,而从技术上讲,这并不是一场数据竞赛,它正处于令人沮丧的沮丧之中,我相信这就是Rust本书试图传达的内容:

    use std::collections::HashMap;
    
    fn main() {
        let mut map = HashMap::new();
        map.insert(1, 1);
        map.insert(2, 2);
        map.insert(3, 3);
    
        for _ in map.iter() {
            // given some condition do
            map.insert(4, 4); // uh oh!
        }
    }
    

    playground