I have a template class(LockSpsc) that takes a class as template parameter(InputBuffer) and it should be a reference member of another class(MVMReceiver).
For the sake of clarity:
LockSpsc header:
#ifndef LOCKFREESPSC_H
#define LOCKFREESPSC_H
#include <atomic>
#include <iostream>
#include <type_traits>
#include <vector>
#define CACHE_LINE_SIZE 128
// A simplified version of folly::ProducerConsumerQueue
template <typename T> class LockFreeSpsc
{
public:
LockFreeSpsc(size_t ring_size_)
: _next_read_idx(0),
_next_write_idx(0),
_ring(ring_size_ 1) // one is wasted.
{
// TODO: Use concepts instead
static_assert(std::is_move_assignable_v<T> &&
std::is_move_constructible_v<T>);
}
LockFreeSpsc(const LockFreeSpsc&) = delete;
LockFreeSpsc(LockFreeSpsc&&) = delete ;
bool try_push(T&& t_)
{
const int cur_writer_idx = _next_write_idx.load(std::memory_order_relaxed);
const int cur_reader_idx = _next_read_idx.load(std::memory_order_acquire);
int new_writer_idx = cur_writer_idx 1;
if (new_writer_idx == static_cast<int>(_ring.size()))
{
new_writer_idx = 0;
}
if (new_writer_idx == cur_reader_idx)
{
return false;
}
else
{
_ring[cur_writer_idx] = std::move(t_);
_next_write_idx.store(new_writer_idx, std::memory_order_release);
return true;
}
}
bool try_pop(T& t_)
{
const int cur_reader_idx = _next_read_idx.load(std::memory_order_relaxed);
const int cur_writer_idx = _next_write_idx.load(std::memory_order_acquire);
if (cur_reader_idx == cur_writer_idx)
{
return false;
}
int new_reader_idx = cur_reader_idx 1;
if (new_reader_idx == static_cast<int>(_ring.size()))
{
new_reader_idx = 0;
}
// Got something to read
t_ = std::move(_ring[cur_reader_idx]);
_next_read_idx.store(new_reader_idx, std::memory_order_release);
return true;
}
void print()
{
std::cout << "Ring "
<< ", cur r " << _next_read_idx << ", cur w " << _next_write_idx
<< std::endl;
for (size_t i = 0; i < _ring.size(); i)
{
std::cout << _ring[i] << std::endl;
}
}
private:
std::atomic_int _next_read_idx;
char padding1[CACHE_LINE_SIZE - sizeof(std::atomic_int)];
std::atomic_int _next_write_idx;
char padding2[CACHE_LINE_SIZE - sizeof(std::atomic_int)];
std::vector<T> _ring;
};
#endif // ! LOCKFREESPSC_H
InputBuffer header:
#ifndef INPUTBUFFER_H
#define INPUTBUFFER_H
#include <boost/asio/buffer.hpp>
#include <boost/asio/io_context.hpp>
#include <boost/asio/ip/udp.hpp>
#include <array>
const int MB = 1024 * 1024;
using namespace boost;
using namespace boost::asio;
struct InputBuffer
{
constexpr static int64_t MTU = 1500;
InputBuffer() = default;
InputBuffer(const InputBuffer&) = default;
InputBuffer(InputBuffer&&) = default;
InputBuffer& operator=(InputBuffer&&) = default;
struct Header
{
int32_t frame_id{};
int32_t part_begin{};
int16_t part_id{};
int16_t total_parts{};
int32_t part_size{};
friend std::ostream& operator<<(std::ostream& o, const Header& h)
{
o << "Frame id: " << h.frame_id << ", part num: " << h.part_id
<< ", part begin: " << h.part_begin;
return o;
}
};
Header get_header() const
{
Header h{};
memcpy(&h, _recv_buff.data(), sizeof(h));
return h;
}
std::pair<Header, ::asio::const_buffer> parse() const
{
Header h = get_header();
return std::make_pair(h, get_frame_part(h.part_size));
}
static size_t size() { return MTU; }
void set_header(const Header& h_)
{
memcpy(_recv_buff.data(), &h_, sizeof(h_));
}
void set_frame_part(::asio::const_buffer buf_)
{
assert(buf_.size() <= writable_size());
memcpy(_recv_buff.data() sizeof(Header), buf_.data(), buf_.size());
}
static size_t writable_size() { return MTU - sizeof(Header); }
::asio::mutable_buffer data()
{
return ::asio::mutable_buffer(_recv_buff.data(), _recv_buff.size());
}
::asio::const_buffer buffer() const
{
return ::asio::const_buffer(_recv_buff.data(), _recv_buff.size());
}
private:
::asio::const_buffer get_frame_part(size_t part_size_) const
{
return ::asio::const_buffer(_recv_buff.data() sizeof(Header), part_size_);
}
std::array<char, MTU> _recv_buff{0};
};
#endif // ! INPUTBUFFER_H
Problem:
In my receiver class, I declare it this way:
class Receiver
{
...
LockFreeSpsc<InputBuffer>& m_disruptor;
}
And here's initializer list:
Receiver::Receiver()
: m_disruptor(LockFreeSpsc<InputBuffer>(10000))
The error I get is:
this was 0x38.
_BUF_SIZE 8 const unsigned __int64
this 0x0000000000000038 {_Bx={_Buf=0x0000000000000040 <Error reading characters of string.> _Ptr=??? _Alias=...} ...} std::_String_val<std::_Simple_types<wchar_t>> *
What am I doing wrong?
CodePudding user response:
You don't provide accurate information about the problem you encounter. I checked your code and it should work fine considering some exceptions under some circumstances.
The error below(you get) clearly says that it's about reading characters of string:
this 0x0000000000000038 {_Bx={_Buf=0x0000000000000040 <Error reading characters of string.> _Ptr=??? _Alias=...} ...} std::_String_val<std::_Simple_types<wchar_t>> *
As already I said, the code you shared works fine and I don't think that the error you get is about the part of the code/code snippets you shared.