演示如何使用消息对实现线程同步(C++代码)

文章介绍了在C++中使用std::queue和std::deque进行线程间消息传递的示例,以及如何通过SynchronizedBuffer类封装同步逻辑。讨论了std::queue的先进先出特性与std::deque的双向操作在不同场景下的适用性。
摘要由CSDN通过智能技术生成
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <queue>

// Define a message structure
struct Message {
    int senderId;
    std::string content;
};

// Global variables for synchronization
std::mutex mtx;
std::condition_variable cv;
std::queue<Message> messageQueue;

// Function for sending a message
void sendMessage(int senderId, const std::string& content) {
    std::lock_guard<std::mutex> lock(mtx);
    messageQueue.push({senderId, content});
    cv.notify_one(); // Notify the waiting thread
}

// Function for receiving a message
void receiveMessage(int receiverId) {
    std::unique_lock<std::mutex> lock(mtx);
    cv.wait(lock, [] { return !messageQueue.empty(); }); // Wait until there is a message

    // Process the message
    Message msg = messageQueue.front();
    messageQueue.pop();

    // Check if the message is for this receiver
    if (msg.senderId == receiverId) {
        std::cout << "Received message: " << msg.content << std::endl;
    } else {
        std::cout << "Message not for this receiver" << std::endl;
    }
}

int main() {
    // Create sender and receiver threads
    std::thread senderThread([] {
        sendMessage(1, "Hello from sender");
        sendMessage(2, "Hello from sender");
    });

    std::thread receiverThread1([] {
        receiveMessage(1);
    });

    std::thread receiverThread2([] {
        receiveMessage(2);
    });

    // Join threads
    senderThread.join();
    receiverThread1.join();
    receiverThread2.join();

    return 0;
}

        这个例子中:

                ①. 定义一个 Message 结构来保存发送者ID信息和内容的相关信息。

                ②. 全局变量 mtx , cv 和 messageQueue 用于同步。 mtx 是std::mutex变量, cv 是std::condition_variable变量, messageQueue 是用于存储消息的std::queue队列

                ③. 线程使用 sendMessage 函数发送消息。它锁定互斥项,将消息推入队列,并使用条件变量通知等待的线程。

                ④.  receiveMessage 函数用于线程接收消息。它使用条件变量等待队列中出现消息。一旦有消息,它就会处理该消息。

                ⑤. 在 main 函数中,我们创建了发送者和接收者线程,以演示线程之间的消息传递。

        本示例说明了使用消息对同步线程的基本方法。根据您的具体要求和使用情况,您可能需要修改或扩展这种方法。

std::queue和std::deque,在C++中哪个更好?

        在 C++ 中, std::queuestd::deque 的作用各不相同,是否适用取决于应用程序的具体需求:

        ①.  std::deque (双端队列)是一种允许在前后两端插入和删除的容器。其实现方式是在两端快速插入和删除。 std::deque 是一种序列容器,可以像动态数组一样使用,并能在两端增长和收缩

        ②.  std::queue 是一种容器适配器,为您提供 FIFO(先进先出)行为。它通常使用 std::deque 或 std::list 作为底层容器,提供一系列受限的操作,如 enqueue(推送)、dequeue(弹出)和 front。

哪个更好?

       ①. 性能考虑因素:如果需要在序列两端快速插入和删除,那么 std::deque 是更好的选择。但是,如果只需要在后端插入并从前端删除, std::queue 则为先进先出队列提供了更合适、语义更清晰的接口。 

        ②. 内存效率:与基于 std::list std::queue 相比, std::deque 可能会更有效地使用内存std::deque的效率更高,因为std::deque以块为单位分配元素,与std::list 相比,减少了开销,因为 std::list 中的每个元素都需要分配自己的内存。

        ③. 功能需求:如果您需要一个简单的队列结构,并且不需要访问容器的中间部分, std::queue 是合适的选择。如果您需要更灵活的操作,如访问中间的元素、从两端插入或移除元素,那么 std::deque 会更好。

        ④. 语义清晰:使用 std::queue 可以清楚地表明您使用的是先进先出数据结构,这可以使代码更容易理解,而 std::deque 则更为通用,并不暗示特定的使用模式

        总之,选择 std::queue 还是 std::deque 取决于您的具体需求。如果您需要简单的 FIFO 结构, std::queue 是典型的选择。如果您需要在两端插入和删除数据时具有更高的灵活性和性能, std::deque 则是更好的选择。

在一个类中定义

        为了将同步机制和缓冲区管理封装在一个类中,我们可以定义一个类来管理共享缓冲区,并提供线程安全的方法来生成和消耗项目。下面是定义此类的方法:

        ①. Buffer Class:该类将包含作为缓冲区的 std::deque 以及用于同步的 std::mutexstd::condition_variable

        ②. 生产者和消费者方法:这些方法是类的一部分,将使用同步原语安全地访问缓冲区。

        下面是一个如何定义和使用这种类的示例:

#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <deque>

class SynchronizedBuffer {
private:
    std::mutex mtx;
    std::condition_variable cv;
    std::deque<int> buffer;
    const size_t maxSize;
    bool finished;

public:
    SynchronizedBuffer(size_t maxSize) : maxSize(maxSize), finished(false) {}

    void produce(int item) {
        std::unique_lock<std::mutex> lock(mtx);
        cv.wait(lock, [this] { return buffer.size() < maxSize; });
        buffer.push_back(item);
        std::cout << "Produced: " << item << std::endl;
        lock.unlock();
        cv.notify_one();
    }

    int consume() {
        std::unique_lock<std::mutex> lock(mtx);
        cv.wait(lock, [this] { return !buffer.empty() || finished; });
        if (buffer.empty()) {
            return -1; // or other sentinel value indicating no more items will be produced
        }
        int item = buffer.front();
        buffer.pop_front();
        std::cout << "Consumed: " << item << std::endl;
        lock.unlock();
        cv.notify_one();
        return item;
    }

    void finish() {
        std::unique_lock<std::mutex> lock(mtx);
        finished = true;
        cv.notify_all();
    }
};

void producer(SynchronizedBuffer& buffer, int start, int end) {
    for (int i = start; i < end; ++i) {
        buffer.produce(i);
    }
    buffer.finish();
}

void consumer(SynchronizedBuffer& buffer) {
    while (true) {
        int item = buffer.consume();
        if (item == -1) break;
        // Process the item
    }
}

int main() {
    SynchronizedBuffer buffer(10);

    std::thread prod1(producer, std::ref(buffer), 0, 50);
    std::thread cons1(consumer, std::ref(buffer));

    prod1.join();
    cons1.join();

    return 0;
}

        finish方法允许生产者发出不再生产项目的信号,这有助于优雅地终止消费者线程。

        这种结构将同步逻辑封装在 SynchronizedBuffer 类中,使多线程逻辑更易于管理和理解。

  • 18
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值