首頁 >後端開發 >C++ >Rust 線路安全性:與 C 的比較。

Rust 線路安全性:與 C 的比較。

Susan Sarandon
Susan Sarandon原創
2024-11-19 11:54:02820瀏覽

在這個POC(概念證明)中,我們將探索Rust語言如何處理競爭條件,並將其與C ,一種廣泛使用的語言,但競爭的安全保障較少。

Rust 線路安全性:與 C 的比較

執行緒安全:從 C 到 Rust 的資料競爭

指數

    一、簡介
  • 2. 執行緒
  • 3. C 語言的實現
    • 3.1.沒有針對競爭條件的保護的程式碼
    • 3.2.使用互斥體修復
  • 4. Rust 中的實現
    • 4.1.競爭條件問題
    • 4.2.互斥體和弧的解析
    • 4.3.互斥體對比讀寫鎖
  • 5. 結論
  • 6. 參考文獻

一、簡介

在計算中,

執行緒用於將軟體任務分割為可以並發執行的子任務。透過使用線程,我們獲得了處理時間並更好地利用機器的資源,但這種競爭帶來了挑戰,例如競爭條件,這可能會產生數據的嚴重不一致。


2. 執行緒

執行緒是允許您同時處理任務的執行單元。我們可以將執行緒視為程式內獨立的執行流,如下圖所示:

Rust Threads safety: Uma comparação com C.

雖然執行緒帶來了效能優勢,但它們也帶來了風險,尤其是在存取共享資源時。

此外,執行緒還可以用來實現並行性,即多個任務在不同的CPU核心上同時執行。這使得程式能夠更好地利用可用的硬件,加快獨立任務的執行速度。


3. C 語言的實現

讓我們在

C 中建立一個簡單的系統:

    初始餘額為 1000。
  1. 一組可以是貸方或借方的交易。
  2. 使用執行緒並行處理這些事務。
3.1.沒有針對競爭條件的保護的程式碼

int saldo = 1000; 

void creditar(int valor) {
    int tmp_saldo = saldo;

    sleep(1); // Delay simulado

    saldo += tmp_saldo + valor;
}

void debitar(int valor) {
    int temp = saldo;

    sleep(1); // Delay simulado

    if (temp >= valor) {
        saldo = temp - valor;
    }
}

void* processar_transacao(void* arg) {
    int valor = *(int*)arg;

    if (valor > 0) {
        creditar(valor);
    } else {
        debitar(abs(valor));
    }

    return NULL;
}

int main() {
    int transactions[] = {100, -50, 200, -150, 300, -200, 150, -100, 50, -50};
    int num_transactions = sizeof(transactions) / sizeof(transactions[0]);

    pthread_t threads[num_transactions];

    for (int i = 0; i < num_transactions; i++) {
        pthread_create(&threads[i], NULL, processar_transacao, &transactions[i]); // Cria uma thread para cada transação
    }

    for (int i = 0; i < num_transactions; i++) {
        pthread_join(threads[i], NULL); // Aguarda todas as threads terminarem
    }

    printf("Saldo final da conta: %d\n", saldo);
    return 0;
}
當我們選擇具有

多執行緒處理的環境時,我們所說的競爭條件可能會發生,當兩個執行緒存取並修改相同的值時,我們就會出現競爭條件。出現此問題的原因是,由於呼叫之間的競爭,無法保證每個執行緒中存取的值的同步。

多次執行此程式碼時,最終餘額會有所不同,因為執行緒同時存取和更改餘額。

Rust Threads safety: Uma comparação com C.


3.2.使用互斥體修復

int saldo = 1000; 

void creditar(int valor) {
    int tmp_saldo = saldo;

    sleep(1); // Delay simulado

    saldo += tmp_saldo + valor;
}

void debitar(int valor) {
    int temp = saldo;

    sleep(1); // Delay simulado

    if (temp >= valor) {
        saldo = temp - valor;
    }
}

void* processar_transacao(void* arg) {
    int valor = *(int*)arg;

    if (valor > 0) {
        creditar(valor);
    } else {
        debitar(abs(valor));
    }

    return NULL;
}

int main() {
    int transactions[] = {100, -50, 200, -150, 300, -200, 150, -100, 50, -50};
    int num_transactions = sizeof(transactions) / sizeof(transactions[0]);

    pthread_t threads[num_transactions];

    for (int i = 0; i < num_transactions; i++) {
        pthread_create(&threads[i], NULL, processar_transacao, &transactions[i]); // Cria uma thread para cada transação
    }

    for (int i = 0; i < num_transactions; i++) {
        pthread_join(threads[i], NULL); // Aguarda todas as threads terminarem
    }

    printf("Saldo final da conta: %d\n", saldo);
    return 0;
}

互斥體是一種同步原語,可確保一次只有一個執行緒可以存取共享資源。縮寫互斥體來自英文術語互斥,意思是「互斥」。

當一個執行緒取得互斥體時,任何其他嘗試取得相同互斥體的執行緒都會被掛起,直到第一個執行緒釋放互斥體。這可以防止兩個或多個進程(執行緒)同時存取共享資源。

Rust Threads safety: Uma comparação com C.

4. Rust 中的實現

int saldo = 1000; 
pthread_mutex_t saldo_mutex; // Mutex para proteger o saldo

void creditar(int valor) { 
    pthread_mutex_lock(&saldo_mutex); // Bloqueia o mutex
    int tmp_saldo = saldo;

    sleep(1); // Delay simulado

    saldo = tmp_saldo + valor;

    pthread_mutex_unlock(&saldo_mutex); // Libera o mutex
}

void debitar(int valor) {
    pthread_mutex_lock(&saldo_mutex); // Bloqueia o mutex
    int tmp_saldo = saldo;

    sleep(1); // Delay simulado

    if (tmp_saldo >= valor) {
        saldo = tmp_saldo - valor;
    }

    pthread_mutex_unlock(&saldo_mutex);  // Libera o mutex
}

將Rust 視為一種不存在於資料競賽中的語言並不高效,但我們可以理解結構 及其編譯器如何透過為記憶體和執行緒安全帶來出色的功能來做出貢獻。

Rust 使用 所有權借用 和並發安全結構等功能,透過編譯時保證來對待競爭條件

  • Arc:安全共享不可變資料。
  • MutexRwLock:可變資料的存取控制。

4.1.競爭條件問題

不使用 Arc 和 Mutex 結構

Rust’s rich type system and ownership model guarantee memory-safety and thread-safety — enabling you to eliminate many classes of bugs at compile-time.

Rust 不允許在沒有保護的情況下從多個線程直接存取可變資料(餘額)。
編譯器將產生錯誤,因為餘額在沒有安全機制的情況下被移動到多個執行緒(handle1handle2)。
將顯示的錯誤訊息是:

fn main() {
    let mut saldo = 1000; // saldo mutável, mas sem proteção

    let handle1 = thread::spawn(move || {
        saldo += 100;  // erro: `saldo` é movido para esta thread sem proteção
    });

    let handle2 = thread::spawn(move || {
        saldo -= 50;  // erro: `saldo` é movido para esta thread sem proteção
    });

    handle1.join().unwrap();
    handle2.join().unwrap();
}

4.2.互斥體和弧的解析

使用 Mutex 和 Arc,我們能夠編譯並執行我們的程式碼,並解決了競爭條件問題。

error[E0382]: use of moved value: `saldo`

4.3.互斥體對比讀寫鎖

Mutex 和 RwLock 用來處理競爭條件,各自具有特定的優點:

互斥體:保證一個執行緒對資源的獨佔訪問,阻止對其他執行緒的訪問,直到該執行緒被釋放。它簡單而有效,但即使是讀取也會阻塞資源,從而在讀取密集的場景中效率較低

RwLock:使用 .read() 允許多個同時讀取,並使用 .write() 限制獨佔寫入。它非常適合以讀取為主的場景,因為它透過允許讀取操作中的並行性來提高效能。


5. 結論

C 和 Rust 之間的比較突顯了解決競爭條件的不同方法。 C 需要注意避免競爭條件錯誤,而 Rust 除了所有權模型之外還透過 Mutex、RwLock 和 Arc 等工具在編譯時降低了這些風險。這不僅使程式碼更加安全,還透過避免無聲錯誤減少了程式設計師的心理負擔

總之,Rust 將自己定位為開發競爭系統的絕佳選擇,提供安全性和可靠性。


6. 參考文獻

  • 附程式碼的倉庫:https://github.com/z4nder/rust-data-races
  • https://en.wikipedia.org/wiki/Race_condition
  • https://blog.bughunt.com.br/o-que-sao-vulnerabilidades-race-condition/
  • https://medium.com/cwi-software/spring-boot-race-condition-e-ambiente-multi-thread-263b21e0042e
  • https://learn.microsoft.com/en-us/troubleshoot/developer/visualstudio/visual-basic/language-compilers/race-conditions-deadlocks
  • https://www.reddit.com/r/rust/comments/18faxjg/understanding_threadsafety_vs_race_conditions/?rdt=52263
  • https://doc.rust-lang.org/nomicon/races.html
  • https://news.ycombinator.com/item?id=23599598

以上是Rust 線路安全性:與 C 的比較。的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn