针对大数组(10^7元素)的信号处理,我使用不同的线程连接环形缓冲区。不幸的是,太多的时间都用于将数据复制到和复制出缓冲区。当前实现基于boost::lockfree::spsc_queue。
因此,我正在寻找一种解决方案,通过使用unique_ptr来交换向量在线程和缓冲区之间的所有权(请参见附加的图纸:在线程和队列之间交换指针)。
移动智能指针并不符合我的需求,因为这样我需要不断在运行时为新的向量元素分配内存。这个开销比数据传输大得多。
在这个设计中,我是否忽略了一些缺陷?
是否有线程安全或甚至无锁的环形缓冲区实现,允许推入和弹出的交换操作?
编辑:我修改了一个锁定的环形缓冲区来交换 unique_ptr。性能提升很大。虽然它不像一个优雅的解决方案。有什么建议吗?
因此,我正在寻找一种解决方案,通过使用unique_ptr来交换向量在线程和缓冲区之间的所有权(请参见附加的图纸:在线程和队列之间交换指针)。
移动智能指针并不符合我的需求,因为这样我需要不断在运行时为新的向量元素分配内存。这个开销比数据传输大得多。
在这个设计中,我是否忽略了一些缺陷?
是否有线程安全或甚至无锁的环形缓冲区实现,允许推入和弹出的交换操作?
编辑:我修改了一个锁定的环形缓冲区来交换 unique_ptr。性能提升很大。虽然它不像一个优雅的解决方案。有什么建议吗?
// https://github.com/embeddedartistry/embedded-resources/blob/master/examples/cpp/circular_buffer.cpp
#include <memory>
#include <mutex>
template <typename T, int SIZE>
class RingbufferPointer {
typedef std::unique_ptr<T> TPointer;
public:
explicit RingbufferPointer() {
// create objects
for (int i=0; i<SIZE; i++) {
buf_[i] = std::make_unique<T>();
}
}
bool push(TPointer &item) {
std::lock_guard<std::mutex> lock(mutex_);
if (full())
return false;
std::swap(buf_[head_], item);
if (full_)
tail_ = (tail_ + 1) % max_size_;
head_ = (head_ + 1) % max_size_;
full_ = head_ == tail_;
return true;
}
bool pop(TPointer &item) {
std::lock_guard<std::mutex> lock(mutex_);
if (empty())
return false;
std::swap(buf_[tail_], item);
full_ = false;
tail_ = (tail_ + 1) % max_size_;
return true;
}
void reset() {
std::lock_guard<std::mutex> lock(mutex_);
head_ = tail_;
full_ = false;
}
bool empty() const {
return (!full_ && (head_ == tail_));
}
bool full() const {
return full_;
}
int capacity() const {
return max_size_;
}
int size() const {
int size = max_size_;
if(!full_) {
if(head_ >= tail_)
size = head_ - tail_;
else
size = max_size_ + head_ - tail_;
}
return size;
}
private:
TPointer buf_[SIZE];
std::mutex mutex_;
int head_ = 0;
int tail_ = 0;
const int max_size_ = SIZE;
bool full_ = 0;
};