std::vector::erase() (多线程) '断言 'px != 0' 失败。
std::vector::erase() (multithreaded) 'Assertion `px != 0' failed.'
类似于 shared_ptr 断言 px != 0 失败
我正在编写一个游戏服务器,它会生成一个新线程来处理每个用户会话。主线程有一个 std::vector 的 UserSession 共享指针。另一个线程定期从此向量中删除死会话,但在执行 std::vector::erase(( 时失败。我无法找出我的生活出了什么问题。
错误是:
原型 2:/usr/include/boost/smart_ptr/shared_ptr.hpp:653: typename boost::d etail::sp_member_access::type boost::shared_ptr::operator->(( const [with T = UserSession; typename boost::d etail::sp_member_access::type = UserSession*]: 断言 'px != 0' 失败。 已中止(核心已转储(
相关代码为:
void GameServer::start()
{
int sessionid;
boost::asio::io_service io_service;
tcp::acceptor acceptor(io_service, tcp::endpoint(tcp::v4(), port_));
boost::thread(&GameServer::session_monitor, this);
for (;;)
{
socket_shptr socket(new tcp::socket(io_service));
acceptor.accept(*socket);
sessionid = numsessions_++;
UserSession* usession = new
UserSession(socket, sessionid, io_service);
session_shptr session(usession);
sessions_mutex_.lock();
sessions_.push_back(session);
sessions_mutex_.unlock();
std::cout << "Starting session for client " <<
get_client_ip(*socket) << std::endl;
session->start();
}
}
void GameServer::session_monitor()
{
for (;;)
{
boost::this_thread::sleep(boost::posix_time::seconds(10));
std::cout << "Removing dead user sessions" << std::endl;
sessions_mutex_.lock();
for (std::vector<session_shptr>::iterator it = sessions_.begin();
it != sessions_.end(); ++it)
{
if ((*it)->is_dead())
{
std::cout << "Removing session: " << (*it)->id() <<
std::endl;
sessions_.erase(it);
}
}
sessions_mutex_.unlock();
}
}
在迭代器上调用erase
会使它失效。然后,您尝试继续使用它来循环访问列表。需要使用返回值 erase
继续循环访问列表。
for (std::vector<session_shptr>::iterator it = sessions_.begin(); it != sessions_.end(); )
{
if ((*it)->is_dead())
{
std::cout << "Removing session: " << (*it)->id() <<
std::endl;
it = sessions_.erase(it);
}
else
++it;
}
从std::vector
中删除内容的正确方法是使用删除-擦除习惯用法。 循环访问容器并手动删除元素既烦人又不会更有效率,而且很容易出错,因为erase
会使您的迭代器失效。
std::remove
和std::remove_if
已经是非常巧妙的实现,我们可以将它们与调用erase
捆绑在一起,这样您编写的唯一代码就是从一种擦除到另一种擦除不同的代码。
以下是此习惯用法的基于容器的版本:
template<typename Container, typename Lambda>
Container&& remove_erase_if( Container&& c, Lambda&& test ) {
using std::begin; using std::end;
auto it = std::remove_if( begin(c), end(c), std::forward<Lambda>(test) );
c.erase(it, c.end());
return std::forward<Container>(c);
}
template<typename Container, typename T>
Container&& remove_erase( Container&& c, T&& test ) {
using std::begin; using std::end;
auto it = std::remove( begin(c), end(c), std::forward<T>(test) );
c.erase(it, c.end());
return std::forward<Container>(c);
}
现在你的代码读起来是这样的:
sessions_mutex_.lock();
remove_erase_if( sessions_, []( session_shptr& ptr )->bool {
if (ptr->is_dead()) {
std::cout << "Removing session: " << ptr->id() << std::endl;
ptr.reset(); // optional
return true;
} else {
return false;
}
});
sessions_mutex_.unlock();
或者,更短:
sessions_mutex_.lock();
remove_erase_if( sessions_, []( session_shptr& ptr ) {
return ptr->is_dead();
});
sessions_mutex_.unlock();
作为最后一个问题,请注意,如果你的析构函数可以重入,你必须非常小心你的std::vector
的状态 - 如果析构函数代码导致你正在处理的vector
被更改,你就有麻烦了。
如果这是一个问题,您可以创建一个临时向量来填充死进程:
std::vector<session_shptr> tmp;
sessions_mutex_.lock();
remove_erase_if( sessions_, []( session_shptr& ptr ) {
if (!ptr->is_dead())
return false;
tmp.emplace_back( std::move(ptr) );
return true;
});
sessions_mutex_.unlock();
tmp.clear();
它将会话的销毁移出锁(好!(,并将其移出在几乎全局可访问vector
上迭代的代码(太好了!(。
这确实使用了一些 C++11 构造,但如果编译器是纯 C++03 而不会造成太大损害,则可以删除大多数构造。 (去掉forward
s,将&&
替换为Container
上的&
,并将&&
替换为Lambda
和T
上的const &
(。
您必须将 lambda 编写为函数或函数对象或erase_remove_if
调用的bind
。
- 尝试使用 std::vector<std::thread时出现静态断言失败错误>
- uint_not_usable_without_attribute在业力规则中使用数字生成器时静态断言失败
- 从 exe 文件 (Visual Studio ) 启动时调试断言失败
- 断言"id < 0"在Qt ActiveX中失败
- 在 CppUnit 中测试中止断言失败
- 使用扫描的调试断言失败
- MS 本机单元测试 - 断言::线程失败不起作用
- 为什么我的Qt程序在断言失败后继续运行?
- 图片不显示,关闭时出错 --> 调试断言失败!表达式:is_block_type_valid(标头>_block_use)
- 访问提升:shared_ptr 主范围外崩溃,断言失败:px != 0.指针的正确用法是什么?
- C++ 调试断言失败 - 矢量下标超出视觉工作室的范围
- 错误:断言失败 (src.type() == CV_8UC1) 在阈值中
- Boost Beast 异步服务器失败,断言失败:(id_ != T::id) 在多个 aync 调用中
- 使用imwrite OpenCV时断言失败
- 调试断言失败的缓冲区!=nullptr
- 使用 ofstream 写入文本文件时断言失败
- OpenCV 错误:相机校准:断言在matrix_wrap.cpp失败
- 提升继续恢复断言失败
- 获取有关调试断言失败的错误:表达式:"(_Ptr_user &(_BIG_ALLOCATION_ALIGNMENT -1)) == 0" &&0
- 打破gdb中失败断言的正确方法是什么