簡體   English   中英

通過shared_ptr訪問寫入方法時,async_write上出現C ++ Boost.Asio分段錯誤

[英]C++ Boost.Asio Segmentation Fault on async_write while accessing write-method through shared_ptr

我創建了一個靜態映射,其中包含幾個連接的客戶端的會話。

std::map<std::string, std::shared_ptr<Session>> Communication::m_appSockets;

接受傳入客戶端的偵聽器在Communication類中實現。

class Communication : public std::enable_shared_from_this<Communication>
{
private:
  boost::asio::io_context m_ioc;
  boost::asio::io_context::work m_work;
  boost::asio::streambuf m_buffer;
  boost::asio::ip::tcp::acceptor m_acceptor;
  std::thread m_senderThread;
  std::thread m_ioThread;

public:
  static std::map<std::string, std::shared_ptr<Session>> m_appSockets;

  Communication(uint16_t t_port);

  void accept();

  void doAccept();

  void senderThread();
};

接受客戶端后,方法“ doAccept”將創建一個會話對象並像這樣移動套接字

  m_acceptor.async_accept(
    [this](boost::system::error_code t_ec, boost::asio::ip::tcp::socket t_socket) {
      if (!t_ec)
      {
            m_appSockets.emplace(std::pair<std::string, std::shared_ptr<Session>>(
              "app0", std::make_shared<Session>(std::move(t_socket))));
            m_appSockets["app0"]->start();
      }
      accept();
    });

Session.h看起來像這樣:

class Session : public std::enable_shared_from_this<Session>
{
private:
  boost::asio::ip::tcp::socket m_socket;
  boost::asio::streambuf m_buffer;

public:

  Session(boost::asio::ip::tcp::socket t_socket);

  void write(std::string &t_msg);
  void doWrite(std::string &t_msg);
  void start();
...
};

void start()用於啟動套接字上的異步讀取,可以正常工作。 通過以下方式創建會話對象:

Session::Session(boost::asio::ip::tcp::socket t_socket) : m_socket(std::move(t_socket))
{}

對於我的實現,我需要做的是通過Communication.h映射中的shared_ptr訪問會話的寫方法。 我嘗試了以下方法

void Communication::senderThread()
{
  for (;;)
  {
    .... 
    //blocking until queue holds a message
    std::string buf = *message from queue*//pseudo code
    m_appSockets["app0"].get()->write(buf);

  }
}

senderthread阻塞,直到隊列中有可用消息為止,該消息將被轉發到會話的write方法

可以調用寫方法,但是一旦我在會話的任何成員上嘗試操作,就會給我帶來分段錯誤:

void Session::write(std::string &t_msg)
{
//here it crashes
  m_socket.get_executor().context().post(std::bind(&Session::doWrite, shared_from_this(), t_msg));
}

void Session::doWrite(std::string &t_msg)
{
  boost::asio::async_write(
    m_socket, boost::asio::buffer(t_msg),
    std::bind(&Session::onWrite, shared_from_this(), std::placeholders::_1, std::placeholders::_2));
}

當我輸入其方法后,就好像Session對象超出了范圍。 我嘗試在Session中創建虛擬成員,這些虛擬成員在訪問它們時均給出了相同的分段錯誤。 我在某個時候弄錯了shared_ptr / object的生命周期嗎?

提前非常感謝您。

編輯1:運行gdb ./programm.out核心給了我這個:

線程2“ programm.out”接收到信號SIGSEGV,分段錯誤。 [切換到線程0x7ffff58f1700(LWP 5651)]在/usr/Sources/Session.cpp:58的Session :: write(this = 0x0,t_msg =“ {\\” destination \\“:\\” app0 \\“}”)中的0x0000555555605932 58 std :: cout << dummyMember << std :: endl;

我向會話添加了一個成員(int dummyMember {5};)。

這怎么可能指向0x0?

下線可疑

  boost::asio::buffer(t_msg)

asio::buffer返回一個對象,該對象持有一個指向字符串內容和字符串長度的指針(未創建t_msg的副本)。 在將asio::buffer與異步操作一起使用時,請務必小心,因為其返回類型是字符串的對(指針,長度) ,但它不會延長字符串的壽命。

async_write函數會立即返回,我們不知道何時調用處理程序,因此必須確保msg在調用處理程序之前是有效的。

  for(;;)
  {
    std::string buf = *message from queue*//pseudo code
    m_appSockets["app0"].get()->write(buf);

    // if you want to send original buf string
    // before this loop ends all asynchronous operation writing buf must be complete
  }

如果您的目標是發送msg那么您將錯過使用ref包裝器,因為默認情況下, bind采用參數值。

std::bind(&Session::doWrite, shared_from_this(), t_msg) // make copy of t_msg

上面創建了保存t_msg副本的t_msg 調用此回調時, t_msg副本傳遞到Session::doWrite boost::asio::buffer(t_msg)中。 可能在執行std::bind(&Session::onWrite, shared_from_this(), std::placeholders::_1, std::placeholders::_2)創建的回調之前std::bind(&Session::onWrite, shared_from_this(), std::placeholders::_1, std::placeholders::_2)字符串復制被銷毀並且buffer指向刪除的數據。

您可以使用std::ref重寫Session::write方法:

m_socket.get_executor().context().post(std::bind(&Session::doWrite, shared_from_this(), std::ref(t_msg)));

並確保所有寫入此字符串的異步操作都已完成,直到senderThread for循環結束senderThread 或者,您需要找到另一種在執行異步操作時保留t_msg字符串的方法。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM