Question about concurrency example in Rust book


#1

So in the rust book (https://doc.rust-lang.org/book/concurrency.html) there is this code example:

use std::thread;

fn main() {
    let mut data = vec![1, 2, 3];

    for i in 0..3 {
        thread::spawn(move || {
            data[i] += 1;
        });
    }

    thread::sleep_ms(50);
}

And it says it "is a Rust program that would have a data race in many
languages. " Can someone clarify why? The structure of the data vector is not changed (no elements added or removed, or even searched), so the data[i] access should work ok. And then the += 1 increment should also work ok because each thread only operates on it’s own “i” index… So what’s the problem?


#2

Let’s suppose for the moment that it is not main, but some other function. Then, it can exit before any of the spawn threads starts. Upon exiting, it will free data, and other threads will attempt to access garbage memory. So the race here is between += and the destructor of data.

Caveat: this is main function, so, upon exiting main, all other threads will also terminate. But you still have a data race, because detructor is executing while the main is running.

update: filed an issue about non obvious example https://github.com/rust-lang/rust/issues/31047


#3

Wouldn’t this be more of an issue that you are expecting that data ends up [ 4, 5, 6 ]. However since there is no protection you don’t know what data[i] is when 1 is added to it so data[0] could end up as anything from 2 and 4, likewise data[1] would be be from 3 to 5, and data[2] could be 4 through 6.


#4

No, there is no data races in the addition itself, because you are accessing different elements from each thread. Here is the example, modified to use scoped threads

extern crate crossbeam;

fn main() {
    let mut data = vec![1, 2, 3];

    crossbeam::scope(|scope| {
        for x in &mut data {
            scope.spawn(move || {
                *x += 1;
            });
        }

    });

    println!("{:?}", data);
}

It is data race free and doesn’t use a mutex.


#5

Ah, I see, thanks.