@@ -6,26 +6,28 @@ Safe Rust guarantees an absence of data races, which are defined as:
66* one or more of them is a write
77* one or more of them is unsynchronized
88
9- A data race has Undefined Behavior, and is therefore impossible to perform
10- in Safe Rust. Data races are * mostly* prevented through Rust's ownership system:
9+ A data race has Undefined Behavior, and is therefore impossible to perform in
10+ Safe Rust. Data races are * mostly* prevented through Rust's ownership system:
1111it's impossible to alias a mutable reference, so it's impossible to perform a
1212data race. Interior mutability makes this more complicated, which is largely why
13- we have the Send and Sync traits (see below ).
13+ we have the Send and Sync traits (see the next section for more on this ).
1414
1515** However Rust does not prevent general race conditions.**
1616
17- This is pretty fundamentally impossible, and probably honestly undesirable. Your
18- hardware is racy, your OS is racy, the other programs on your computer are racy,
19- and the world this all runs in is racy. Any system that could genuinely claim to
20- prevent * all * race conditions would be pretty awful to use, if not just
21- incorrect .
17+ This is mathematically impossible in situations where you do not control the
18+ scheduler, which is true for the normal OS environment. If you do control
19+ preemption, it _ can be _ possible to prevent general races - this technique is
20+ used by frameworks such as [ RTIC ] ( https://github.com/rtic-rs/rtic ) . However,
21+ actually having control over scheduling is a very uncommon case .
2222
23- So it's perfectly "fine" for a Safe Rust program to get deadlocked or do
24- something nonsensical with incorrect synchronization. Obviously such a program
25- isn't very good, but Rust can only hold your hand so far. Still, a race
26- condition can't violate memory safety in a Rust program on its own. Only in
27- conjunction with some other unsafe code can a race condition actually violate
28- memory safety. For instance:
23+ For this reason, it is considered "safe" for Rust to get deadlocked or do
24+ something nonsensical with incorrect synchronization: this is known as a general
25+ race condition or resource race. Obviously such a program isn't very good, but
26+ Rust of course cannot prevent all logic errors.
27+
28+ In any case, a race condition cannot violate memory safety in a Rust program on
29+ its own. Only in conjunction with some other unsafe code can a race condition
30+ actually violate memory safety. For instance, a correct program looks like this:
2931
3032``` rust,no_run
3133use std::thread;
@@ -58,6 +60,9 @@ thread::spawn(move || {
5860println!("{}", data[idx.load(Ordering::SeqCst)]);
5961```
6062
63+ We can cause a data race if we instead do the bound check in advance, and then
64+ unsafely access the data with an unchecked value:
65+
6166``` rust,no_run
6267use std::thread;
6368use std::sync::atomic::{AtomicUsize, Ordering};
0 commit comments