資料競爭

當一方儲存器被一方更新而另一方嘗試同時讀取或更新儲存器時(兩者之間沒有同步),就會發生資料爭用。讓我們看一下使用共享計數器的資料競爭的經典示例。

use std::cell::UnsafeCell;
use std::sync::Arc;
use std::thread;

// `UnsafeCell` is a zero-cost wrapper which informs the compiler that "what it
// contains might be shared mutably." This is used only for static analysis, and
// gets optimized away in release builds.
struct RacyUsize(UnsafeCell<usize>);

// Since UnsafeCell is not thread-safe, the compiler will not auto-impl Sync for
// any type containig it. And manually impl-ing Sync is "unsafe".
unsafe impl Sync for RacyUsize {}

impl RacyUsize {
    fn new(v: usize) -> RacyUsize {
        RacyUsize(UnsafeCell::new(v))
    }

    fn get(&self) -> usize {
        // UnsafeCell::get() returns a raw pointer to the value it contains
        // Dereferencing a raw pointer is also "unsafe"
        unsafe { *self.0.get() }
    }

    fn set(&self, v: usize) { // note: `&self` and not `&mut self`
        unsafe { *self.0.get() = v }
    }
}

fn main() {
    let racy_num = Arc::new(RacyUsize::new(0));

    let mut handlers = vec![];
    for _ in 0..10 {
        let racy_num = racy_num.clone();
        handlers.push(thread::spawn(move || {
            for i in 0..1000 {
                if i % 200 == 0 {
                    // give up the time slice to scheduler
                    thread::yield_now();
                    // this is needed to interleave the threads so as to observe
                    // data race, otherwise the threads will most likely be
                    // scheduled one after another.
                }

                // increment by one
                racy_num.set(racy_num.get() + 1);
            }
        }));
    }

    for th in handlers {
        th.join().unwrap();
    }

    println!("{}", racy_num.get());
}

在多核處理器上執行時,輸出幾乎總是小於 10000(10 個執行緒×1000)。

在此示例中,資料爭用產生了邏輯上錯誤但仍然有意義的值。這是因為匹配中只涉及一個單詞 ,因此更新不能部分改變它。但是,當參與競爭物件跨越多個單詞時,資料競爭通常會產生對型別(型別不安全)無效的損壞值,和/或當涉及指標時產生指向無效記憶體位置(記憶體不安全)的值。

但是,仔細使用原子基元可以構建非常有效的資料結構,這些資料結構可能在內部需要執行一些不安全操作來執行 Rust 型別系統無法靜態驗證的操作,但總體上是正確的(即構建一個安全的抽象)。