Home > Blockchain >  Usage of template class as class member gives error reading characters of string
Usage of template class as class member gives error reading characters of string

Time:05-05

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.

  • Related