Maison > développement back-end > C++ > le corps du texte

Sécurité de Rust Threads : une comparaison avec C.

Susan Sarandon
Libérer: 2024-11-19 11:54:02
original
747 Les gens l'ont consulté

Dans ce POC (Proof of Concept), nous explorerons comment le langage Rust traite les conditions de course, en le comparant avec le C , un langage largement utilisé, mais avec moins de garanties de sécurité pour la concurrence.

Sécurité de Rust Threads : une comparaison avec C

Sécurité des threads : course aux données de C à Rust

Indice

  • 1. Présentation
  • 2. Fils
  • 3. Implémentation en C
    • 3.1. Code sans protection contre les conditions de course
    • 3.2. Correction avec Mutex
  • 4. Implémentation dans Rust
    • 4.1. Problème avec les conditions de course
    • 4.2. Résolution avec Mutex et Arc
    • 4.3. Mutex contre RwLock
  • 5. Conclusion
  • 6. Références

1. Présentation

En informatique, les threads sont utilisés pour diviser les tâches logicielles en sous-tâches pouvant être exécutées simultanément. En utilisant des threads, nous gagnons du temps de traitement et utilisons mieux les ressources de la machine, mais cette concurrence apporte des défis, tels que les conditions de concurrence, qui peuvent générer de graves incohérences dans les données.


2. Fils

Les

Threads sont des unités d'exécution qui vous permettent de traiter des tâches simultanément. Nous pouvons considérer les threads comme des flux d'exécution indépendants au sein d'un programme, illustrés dans l'image ci-dessous :

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

Bien que les threads apportent des avantages en termes de performances, ils introduisent des risques, en particulier lors de l'accès à des ressources partagées.

De plus, les threads peuvent être utilisés pour implémenter le parallélisme, dans lequel plusieurs tâches sont exécutées simultanément sur différents cœurs de processeur. Cela permet au programme de mieux utiliser le matériel disponible, accélérant ainsi l'exécution de tâches indépendantes.


3. Implémentation en C

Créons un système simple en C :

  1. Un solde initial de 1000.
  2. Un ensemble de transactions qui peuvent être des crédits ou des débits.
  3. Traitement parallèle de ces transactions à l'aide de threads.

3.1. Code sans protection contre les conditions de course

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;
}
Copier après la connexion
Copier après la connexion

Lorsque nous optons pour un environnement avec traitement multithreading ce que nous appelons des conditions de concurrence peuvent se produire, lorsque 2 threads accèdent et modifient la même valeur, nous avons une condition de concurrence. Ce problème se produit car la synchronisation de la valeur accédée dans chaque thread n'est pas garantie en raison de la concurrence entre les appels.

Lors de l'exécution de ce code plusieurs fois, le solde final varie, à mesure que les threads accèdent et modifient le solde simultanément.

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


3.2. Correction avec Mutex

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;
}
Copier après la connexion
Copier après la connexion

Mutex est une primitive de synchronisation qui garantit qu'un seul thread à la fois a accès à une ressource partagée. L'acronyme mutex vient du terme anglais mutual exclusion, qui signifie « exclusion mutuelle ».

Lorsqu'un thread acquiert un mutex, tout autre thread tentant d'acquérir le même mutex est suspendu jusqu'à ce que le premier thread libère le mutex. Cela empêche deux ou plusieurs processus (threads) d’avoir un accès simultané à la ressource partagée.

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

4. Implémentation dans 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
}
Copier après la connexion

Penser Rust comme un langage absent de la course aux données n'est pas productif, mais nous pouvons comprendre comment les structs et son compilateur contribuent en apportant d'excellentes fonctionnalités pour la mémoire et la sécurité des threads.

Rust traite les conditions de concurrence avec des garanties au moment de la compilation, en utilisant des fonctionnalités telles que la propriété, l'emprunt et des structures sécurisées pour la concurrence :

  • Arc : Partage sécurisé de données immuables.
  • Mutex et RwLock : Contrôle d'accès aux données mutables.

4.1. Problème avec les conditions de course

Sans utilisation de structures Arc et 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.
Copier après la connexion

Rust ne permet pas l'accès direct aux données mutables (solde) à partir de plusieurs threads sans protection.
Le compilateur générera une erreur car le solde est déplacé vers plusieurs threads (handle1 et handle2) sans mécanisme sécurisé.
Le message d'erreur qui s'affichera est :

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();
}
Copier après la connexion

4.2. Résolution avec Mutex et Arc

Grâce à Mutex et Arc, nous avons pu compiler et exécuter notre code, en résolvant les problèmes de condition de concurrence.

error[E0382]: use of moved value: `saldo`
Copier après la connexion

4.3. Mutex contre RwLock

Mutex et RwLock sont utilisés pour gérer les conditions de course, chacune avec des avantages spécifiques :

Mutex : garantit un accès exclusif à une ressource pour un thread, bloquant l'accès aux autres jusqu'à sa libération. C'est simple et efficace, mais même les lectures bloquent la ressource, la rendant moins efficace dans les scénarios de lecture lourde.

RwLock : autorise plusieurs lectures simultanées avec .read() et restreint l'écriture exclusive avec .write(). Il est Idéal pour les scénarios avec une prédominance de lectures, car il améliore les performances en permettant le parallélisme dans les opérations de lecture.


5. Conclusion

La comparaison entre C et Rust met en évidence différentes approches pour résoudre les conditions de course. Alors que C nécessite une attention particulière pour éviter les erreurs de condition de concurrence, Rust réduit ces risques au moment de la compilation, grâce à des outils tels que Mutex, RwLock et Arc en plus du modèle de propriété. Cela rend non seulement le code plus sécurisé, mais également réduit la charge mentale du programmeur en évitant les bugs silencieux.

En résumé, Rust se positionne comme un excellent choix pour développer des systèmes concurrents, offrant sécurité et fiabilité.


6. Références

  • Repo avec codes : 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/lingual-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

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

source:dev.to
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Derniers articles par auteur
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal