21xrx.com
2024-12-23 00:33:01 Monday
登录
文章检索 我的文章 写文章
C++生产者消费者队列实现
2023-06-22 08:59:58 深夜i     --     --
C++ 生产者消费者模式 队列实现

在多线程编程中,生产者消费者模型是一个非常常见的模型。生产者负责生产数据,而消费者则负责处理这些数据。这两者之间通过一个队列来进行交互,生产者将数据放入队列,而消费者从队列中获取数据进行处理。

C++中实现生产者消费者队列可以使用STL中的queue容器,在多线程环境下需要使用线程安全的容器,例如并发队列concurrent_queue。

生产者消费者队列的实现需要满足以下条件:

1. 线程安全:多个线程同时操作一个队列时需要保证线程安全,不会出现数据竞争的情况。

2. 阻塞式操作:当队列满了或者空了时,生产者和消费者需要进行等待操作,即阻塞式操作。

3. 同步操作:生产者和消费者之间需要实现同步,保证生产者生产的数据能够被消费者及时处理。

以下是一个将STL的queue容器封装成线程安全的生产者消费者队列的代码:


#include <queue>

#include <mutex>

#include <condition_variable>

template<typename T>

class ThreadSafeQueue

{

public:

 ThreadSafeQueue() = default;

 void Push(T value)

 {

  std::lock_guard<std::mutex> lock(mutex_);

  queue_.push(std::move(value));

  cond_.notify_one();

 }

 bool TryPop(T& value)

 {

  std::lock_guard<std::mutex> lock(mutex_);

  if(queue_.empty())

  

   return false;

  

  value = std::move(queue_.front());

  queue_.pop();

  return true;

 }

 void WaitAndPop(T& value)

 {

  std::unique_lock<std::mutex> lock(mutex_);

  while(queue_.empty())

  {

   cond_.wait(lock);

  }

  value = std::move(queue_.front());

  queue_.pop();

 }

 bool Empty() const

 {

  std::lock_guard<std::mutex> lock(mutex_);

  return queue_.empty();

 }

private:

 mutable std::mutex mutex_;

 std::queue<T> queue_;

 std::condition_variable cond_;

};

这里使用了一个mutex和一个condition_variable来实现线程安全的队列。Push操作将数据压入队列中,并通过notify_one通知正在等待的线程。TryPop操作和WaitAndPop操作则将队列中的元素弹出,并返回一个bool类型表示操作是否成功。Empty操作表示队列是否为空。

在使用生产者消费者队列时,需要创建两个线程,一个线程作为生产者,一个线程作为消费者。

以下是一个简单的使用生产者消费者队列的例子:


#include <iostream>

#include <thread>

#include "ThreadSafeQueue.h"

void Producer(ThreadSafeQueue<int>& queue)

{

 for(int i = 0; i < 10; ++i)

 {

  std::cout << "Push " << i << " into queue." << std::endl;

  queue.Push(i);

 }

}

void Consumer(ThreadSafeQueue<int>& queue)

{

 int value = 0;

 while(value != 9)

 {

  if(queue.TryPop(value))

  

   std::cout << "Pop " << value << " from queue." << std::endl;

  

  else

  

   std::cout << "Cannot pop from queue." << std::endl;

  

 }

}

int main()

{

 ThreadSafeQueue<int> queue;

 std::thread producer(Producer, std::ref(queue));

 std::thread consumer(Consumer, std::ref(queue));

 producer.join();

 consumer.join();

 return 0;

}

以上代码中,生产者线程将0~9之间的整数压入队列中,而消费者线程则尝试从队列中弹出数据并输出。当数据为9时,消费者线程退出。在主函数中,创建了一个生产者线程和一个消费者线程,并等待它们两个结束。

综上所述,使用STL中的queue容器实现线程安全的生产者消费者队列是非常简单的,并且能涵盖多线程开发中的大多数需求。通过封装线程安全队列,我们可以更方便地在多线程环境下开发应用程序,提高程序的可读性和可维护性。

  
  

评论区

{{item['qq_nickname']}}
()
回复
回复