4 ms·
I was assuming you were talking about the race & detection as e.g. // let the "race" happen: old = compare_and_swap(some_shared_memory, 1); if old == 0 {
by dbaupp 12y ago
I was assuming you were talking about the race & detection as e.g.
// let the "race" happen:
old = compare_and_swap(some_shared_memory, 1);
if old == 0 {
// we won!
}
This is perfectly valid data-race-free code if the CAS is atomic, but is invalid if the CAS is not (assuming no other memory fences).
But sure, if you're manually fencing then you can have data races that are benign; however, just because something has some relatively rare uses doesn't mean it's wildly unsafe for the general case, and so disallowing by default it helps the correctness of the vast majority of concurrent code.
In any case, Rust allows one to opt-in to that sort of behaviour using `unsafe` locally, e.g. one would use `unsafe` deep in the internals of the implementation of the lock-free data structure and with careful vetting to ensure it's correct, and then all users can benefit with the compiler ensuring concurrency-safety by default.
Rust tries not to completely disallow behaviour, just make memory safety the default. The programmer can override the compiler via `unsafe` if they truly know better.
- asveikau 12y agoOther than the address compare and swap takes two operands: expected value and new value. It does an equality check and (if equal) the swap atomically. Therefore the equality check is handy to atomically check if a previous potentially unsafe read is still valid, and if so, set a new value.
- asveikau 12y agoToo late to edit the post but maybe some code sample will help illustrate the pattern. I am typing code into a web form so I make no guarantees that it is perfect. // Performs some modification on the input. extern int f(int); volatile int global_var = /* ... */; int expected; int new; // assuming C and not C++, where "new" is reserved do { // Do a speculative read expected = global_var; // Make some (non-atomic) modification new = f(expected); // loop until the speculative read was OK. (won the race) } while (compare_and_swap(&global_var, expected, new) != expected);
- dbaupp 12y agoWhoops, I got the signature of CAS slightly wrong. In any case, I already understood the pattern and understand why it is OK. However, as I said, it is the exception that a data race is OK, which is why Rust disallows them by default (it does not disallow them completely).