微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

C++ 中的线程安全 ExpiringDeque 数据结构

如何解决C++ 中的线程安全 ExpiringDeque 数据结构

我正在尝试创建一个数据结构 ExpiringDeque。它应该有点类似于 std::deque 。假设我只需要 push_back()、size() 和 pop_front()。数据结构需要每 T 秒自动过期最多 N 个第一个元素。

这个数据结构需要内部管理自己的队列和过期线程。 如何以线程安全的方式编写它?这是我想出来的一个例子,这看起来合理吗?我错过了什么?

img = cv2.cvtColor(img,cv2.COLOR_GRAY2BGB)

解决方法

您可以通过使用条件变量避免在 ExpiringDeque 的析构函数中进行不必要的等待。我还会使用带有谓词的 std::condition_variable::wait_for 来检查 running_ 标志。这将确保您等待超时或通知,以较早者为准。您避免以这种方式使用 waitCountercontinue

您应该做的另一件事是在检查 pop_front() 中双端队列的大小之前锁定互斥锁,否则它不是线程安全的。

这是您的代码的更新版本:

template <typename T>
class ExpiringDeque {
public:
    ExpiringDeque(int n,int t) : numElements_(n),interval_(t),running_(true),items_({}),cv_() {
        expiringThread_ = std::thread{ [&]() {
          using namespace std::chrono_literals;

          while (true) {
            //Wait for timeout or notification
            std::unique_lock<std::mutex> lk(mutex_);
            cv_.wait_for(lk,interval_ * 1s,[&] { return !running_; });

            if (!running_)
                return;

            //Mutex is locked already - no need to lock again
            int numToErase = std::min(numElements_,static_cast<int>(items_.size()));
            std::cout << "Erasing " << numToErase << " elements\n";
            items_.erase(items_.begin(),items_.begin() + numToErase);
          }
        } };
    }

    ~ExpiringDeque() {
        //Set flag and notify worker thread
        {
            std::lock_guard<std::mutex> lk(mutex_);
            running_ = false;
        }
        cv_.notify_one();
        expiringThread_.join();
    }

    T pop_front() {
        std::lock_guard<std::mutex> guard(mutex_);
        if (items_.size() == 0) {
            throw std::out_of_range("Empty deque");
        }
        T item = items_.front();
        items_.pop_front();
        return item;
    }

    ...

private:
    int numElements_;
    int interval_;

    bool running_;
    std::thread expiringThread_;

    std::mutex mutex_;
    std::deque<T> items_;
    std::condition_variable cv_;
};

您可以将 running_ 标志设为普通 bool,因为 std::condition_variable::wait_for 会自动检查超时或通知。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。