21xrx.com
2024-12-22 22:22:29 Sunday
登录
文章检索 我的文章 写文章
C++并发编程:队列实现
2023-06-29 13:01:29 深夜i     --     --
C++ 并发编程 队列实现 多线程 生产者消费者模式

C++是一种高级编程语言,与其他编程语言一样,它具有一些模板和类可以用于构建队列。队列是一种非常有用的数据结构,经常被用于在并发编程中,以及在许多其他应用程序中。

队列可以看作是一个“先进先出”的集合,其中最先进入队列的元素是最先被取出的。在C++中,队列可以使用STL模板库中的queue类来实现。但是,STL的队列在多线程的情况下可能不是线程安全的,因此需要额外的工作来实现线程安全的队列。

要实现线程安全的队列,我们可以使用互斥锁/临界区。当一个线程需要访问队列时,它会先请求一个锁,如果锁不可用,则该线程会被阻止,并等待锁可用。如果锁可用,该线程就可以使用队列,并在完成任务后释放锁。

以下是一个使用互斥锁/临界区来实现线程安全队列的示例代码:


#include <queue>

#include <mutex>

#include <condition_variable>

template<typename T>

class threadsafe_queue {

private:

  std::queue<T> q;

  mutable std::mutex m;

  std::condition_variable cv;

public:

  threadsafe_queue() = default;

  threadsafe_queue(const threadsafe_queue&) = delete;

  threadsafe_queue& operator=(const threadsafe_queue&) = delete;

  void push(const T& value) {

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

    q.push(value);

    cv.notify_one();

  }

  void wait_and_pop(T& value) {

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

    cv.wait(lock, [this] { return !q.empty(); });

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

    q.pop();

  }

  std::shared_ptr<T> wait_and_pop() {

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

    cv.wait(lock, [this] { return !q.empty(); });

    auto res = std::make_shared<T>(std::move(q.front()));

    q.pop();

    return res;

  }

  bool try_pop(T& value) {

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

    if (q.empty())

      return false;

    

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

    q.pop();

    return true;

  }

  std::shared_ptr<T> try_pop() {

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

    if (q.empty()) {

      return std::shared_ptr<T>();

    }

    auto res = std::make_shared<T>(std::move(q.front()));

    q.pop();

    return res;

  }

  bool empty() const {

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

    return q.empty();

  }

};

此代码使用了std::queue、std::mutex和std::condition_variable来实现一个线程安全的队列。std::queue是C++ STL库中的一个容器适配器,它提供了一个很好的数据结构来实现队列。std::mutex和std::condition_variable是用来实现线程同步和互斥的两个关键工具。

该线程安全队列实现提供了五个基本函数:

1. push() – 将一个元素压入队列;

2. wait_and_pop() – 获取队列中的第一个元素,并且在队列非空时等待;

3. try_pop() – 尝试获取队列中的第一个元素。如果队列已经为空,则该函数不阻塞,并且返回一个空指针;

4. empty() – 检查队列是否为空;

5. wait_and_pop()的重载版本 – 它返回一个存储队列第一个元素副本的std::shared_ptr,从而避免了使用引用参数。

线程安全队列是多线程编程的常见需求。使用互斥锁/临界区来实现一个线程安全的队列并不难,但需要小心地处理并发条件,以避免死锁和竞态条件。上面的示例代码可以作为线程安全队列的一个很好的起点。

  
  

评论区

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