Threadsafe循环缓冲区用于存储指针

时间:2015-06-17 14:10:20

标签: c++ multithreading pointers boost

我目前正在研究一个用于存储指针的线程安全循环缓冲区。作为基础,我使用了此线程中的代码:Thread safe implementation of circular buffer。我的代码如下所示。

因为我想在循环缓冲区中存储指针,所以我需要确保删除已分配的内存,以防缓冲区已满并且第一个元素被覆盖,如boost文档中所述:

  

当circular_buffer变满时,进一步插入将覆盖存储的指针 - 导致内存泄漏。 1

所以我尝试删除add方法中的第一个元素,以防缓冲区已满并且模板的类型T实际上是指针。这会导致C2541错误,因为我尝试删除一个不被视为指针的对象。

我的基本方法是否正确?我该如何解决上述问题?

#pragma once

#include <boost/thread/condition.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/thread.hpp>
#include <boost/circular_buffer.hpp>
#include <type_traits>
#include "Settings.hpp"


template <typename T>
class thread_safe_circular_buffer : private boost::noncopyable
{
public:
    typedef boost::mutex::scoped_lock lock;
    thread_safe_circular_buffer(bool *stop) : stop(stop) {}
    thread_safe_circular_buffer(int n, bool *stop) : stop(stop) {cb.set_capacity(n);}
    void add (T imdata) {
        monitor.lock();
        std::cout << "Buffer - Add Enter, Size: " << cb.size() << "\n";

        if(cb.full())
        {
          std::cout << "Buffer - Add Full.\n";
          T temp = cb.front();

          if(std::is_pointer<T>::value)
            delete[] temp;
        }

        std::cout << "Buffer - Push.\n";
        cb.push_back(imdata);
        monitor.unlock();
        std::cout << "Buffer - Add Exit.\n";
    }
    T get() {
        std::cout << "Buffer - Get Enter, Size: " << cb.size() << "\n";
        monitor.lock();
        while (cb.empty())
        {
        std::cout << "Buffer - Get Empty, Size: " << cb.size() << "\n";
          monitor.unlock();
          std::this_thread::sleep_for(std::chrono::milliseconds(1000));

          if(*stop)
            return NULL;

          monitor.lock();
        }

        T imdata = cb.front();
        // Remove first element of buffer
        std::cout << "Buffer - Pop.\n";
        cb.pop_front();
        monitor.unlock();

        std::cout << "Buffer - Get Exit.\n";
        return imdata;
    }
    void clear() {
        lock lk(monitor);
        cb.clear();
    }
    int size() {
        lock lk(monitor);
        return cb.size();
    }
    void set_capacity(int capacity) {
        lock lk(monitor);
        cb.set_capacity(capacity);
    }

    bool *stop;
private:
    boost::condition buffer_not_empty;
    boost::mutex monitor;
    boost::circular_buffer<T> cb;
};

2 个答案:

答案 0 :(得分:2)

错误告诉您问题:您无法删除不是指针的内容。当T不是指针类型时,delete[] temp;没有意义。如果你的缓冲区存储的内容没有被new[]分配,或者你的循环缓冲区在概念上没有“拥有”,那么这也是一个坏主意。指针。

我想你可能会误解整个问题。升级文档中的警告仅适用于您无法承受“失败”的情况。存储在缓冲区中的任何数据。这是一个问题的一个例子 - 他们特别强调的一个例子 - 是你在缓冲区中存储原始指针,它们是你对动态分配的内存的唯一引用。

我认为,只有三种合理的设计:

  • 当您无法承受丢失数据时,请不要使用循环缓冲区(例如,这可能意味着修改您的数据以便您能够丢失它;例如circular_buffer<unique_ptr<T[]>>用于存储动态分配的数组)。因此,让您的课程不必担心如何处理丢失的数据。
  • 让你的课程采取删除&#39 ;;即一个函数对象,它指定如何处理即将被覆盖的数据元素。 (你可能想要一个默认参数&#34;什么都不做&#34;)
  • 更改缓冲区的功能以执行除完全覆盖以外的其他操作(例如阻止)

答案 1 :(得分:1)

按照提升的方式做:让代码的用户处理这个问题。如果存储了对象,它的析构函数应该处理可能的内存管理,如果指针存储,你无法知道它实际指向的内容:数组,对象,需要释放的内存,在别处管理的内存,而不是动态内存