[英]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.