Maison  >  Article  >  développement back-end  >  Modèles de conception courants dans la programmation simultanée C++

Modèles de conception courants dans la programmation simultanée C++

WBOY
WBOYoriginal
2024-06-02 14:42:56415parcourir

Dans la programmation simultanée C++, l'adoption de modèles de conception peut améliorer la lisibilité, la maintenabilité et l'évolutivité du code. Les modèles courants incluent : le modèle producteur-consommateur : un thread génère des données et d'autres threads consomment des données. Mode lecteur-écrivain : plusieurs lecteurs peuvent accéder aux ressources partagées en même temps, mais un seul rédacteur peut y accéder. Mode moniteur : protège l'accès simultané aux ressources partagées, applique la synchronisation et les contrôles d'état. Mode pool de threads : créez des groupes de threads à l’avance pour éviter la surcharge liée à la création et à la destruction fréquentes de threads.

C++ 并发编程中的常见设计模式

Modèles de conception courants dans la programmation simultanée C++

En programmation simultanée, l'utilisation de modèles de conception peut améliorer considérablement la lisibilité, la maintenabilité et l'évolutivité du code. Vous trouverez ci-dessous quelques modèles courants dans la programmation simultanée C++ :

Modèle producteur-consommateur

Dans ce modèle, un thread producteur génère des données et un ou plusieurs threads consommateurs consomment les données. Les méthodes d'implémentation courantes utilisent des files d'attente ou de la mémoire partagée.

Exemple :

class Producer {
public:
    void produce(const T& data) {
        std::lock_guard<std::mutex> lock(queue_mutex);
        queue.push(data);
    }
private:
    std::queue<T> queue;
    std::mutex queue_mutex;
};

class Consumer {
public:
    void consume() {
        std::unique_lock<std::mutex> lock(queue_mutex);
        if (queue.empty()) {
            condition_variable.wait(lock);
        }
        const T& data = queue.front();
        queue.pop();
        lock.unlock();
        // ...
    }
private:
    std::shared_ptr<Producer> producer;
    std::condition_variable condition_variable;
    std::mutex queue_mutex;
};

Mode lecteur-écrivain

Ce mode permet à plusieurs lecteurs d'accéder à des ressources partagées en même temps, mais un seul écrivain peut y accéder. Des verrous réentrants ou des verrous en lecture-écriture sont souvent utilisés pour implémenter ce modèle.

Exemple :

class ReadWriteLock {
public:
    void read_lock() {
        while (write_locked) {
            unique_lock<std::mutex> lock(read_mutex);
            read_count++;
        }
    }

    void read_unlock() {
        std::lock_guard<std::mutex> lock(read_mutex);
        read_count--;
    }

    void write_lock() {
        std::lock_guard<std::mutex> lock(write_mutex);
        while (read_count > 0) { /* 等待读完成 */}
        write_locked = true;
    }

    void write_unlock() {
        std::lock_guard<std::mutex> lock(write_mutex);
        write_locked = false;
    }

private:
    bool write_locked = false;
    int read_count = 0;
    std::mutex read_mutex;
    std::mutex write_mutex;
};

Modèle de surveillance

Le modèle de surveillance protège l'accès simultané aux ressources partagées en limitant l'accès aux données à un seul objet. Les objets de surveillance encapsulent les données et les opérations et appliquent la synchronisation et la vérification de l'état.

Exemple :

class Account {
public:
    void deposit(int amount) {
        std::lock_guard<std::mutex> lock(balance_mutex);
        balance += amount;
    }

    int withdraw(int amount) {
        std::lock_guard<std::mutex> lock(balance_mutex);
        if (amount <= balance) {
            balance -= amount;
            return amount;
        }
        return 0;
    }

    int get_balance() {
        std::lock_guard<std::mutex> lock(balance_mutex);
        return balance;
    }

private:
    int balance = 0;
    std::mutex balance_mutex;
};

Mode pool de threads

Le mode pool de threads fournit un groupe de threads pré-créé qui peut être utilisé par les threads clients. En utilisant un pool de threads, vous pouvez éviter la surcharge liée à la création et à la destruction fréquentes de threads.

Exemple :

class ThreadPool {
public:
    ThreadPool(int num_threads) {
        for (int i = 0; i < num_threads; i++) {
            threads.emplace_back(std::thread([this] {
                while (true) {
                    std::function<void()> task;
                    {
                        std::unique_lock<std::mutex> lock(tasks_mutex);
                        if (tasks.empty()) {
                            condition_variable.wait(lock);
                        }
                        task = std::move(tasks.front());
                        tasks.pop();
                    }
                    task();
                }
            }));
        }
    }

    void submit(std::function<void()> task) {
        std::lock_guard<std::mutex> lock(tasks_mutex);
        tasks.push(std::move(task));
        condition_variable.notify_one();
    }

private:
    std::vector<std::jthread> threads;
    std::queue<std::function<void()>> tasks;
    std::mutex tasks_mutex;
    std::condition_variable condition_variable;
};

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!

Déclaration:
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