Mos*_*bin 2 c++ boost exception boost-asio blackberry-10
我已将用 C++ 和 Boost 编写的长期稳定库移植到 Blackberry 10。该库在设备之间传输文件。该库编译和链接良好,并且运行良好。但是,在传输 1、2 或 3 个文件后,我始终在我的 Blackberry 10 设备上遇到抛出异常。在源代码中将异常作为 boost::system::system_error 捕获显示它是异常 16,文本为“mutex: Resource busy”。
这是发生异常的源代码:
try
{
. . .
// Find DtpFunctionData for the operation ID, use it to invoke handling function
std::map<int, FunctionData>::iterator iter = _vecFunctionData.find (operationId);
if (iter == _vecDtpClientFunctionData.end ())
return EC_GENERAL_FAILURE;
HANDLINGFUNC_1 handlingFunc = (*iter).second._clientHandlingFunc;
POSTOPFUNC_1 postOpFunc = (*iter).second._clientPostOpFunc;
bool callPostOpOnSuccess = (*iter).second._callPostOpOnSuccess;
// Open a socket opposite the remote peer's TcpPortListener
/* Start: ----- EXCEPTION 16: "mutex: Resource busy" ----- */
boost::asio::io_service io_service;
/* End: ----- EXCEPTION 16: "mutex: Resource busy" ----- */
boost::asio::ip::tcp::socket socket (io_service);
. . .
}
catch (boost::system::system_error& err)
{
LOGLINE (("error", "Boost exception (%d / \"%s\") caught in HandleQueueOperation", err.code ().value(), err.what()));
return EC_EXCEPTION_CAUGHT;
}
Run Code Online (Sandbox Code Playgroud)
跟踪日志行是:
18:37:04 ( 149077264) [error] Boost exception (16 / "mutex: Resource busy") caught in HandleQueueOperation
Run Code Online (Sandbox Code Playgroud)
异常是在上面的“开始”和“结束”注释之间的某个地方抛出的,其中定义了 boost::asio::io_service 对象。我在 StackOverflow、Google 等中搜索了与“互斥:资源繁忙”相关的任何内容,但一无所获。我的代码此时没有访问任何应用程序级别的互斥锁,因此我假设所指的互斥锁是与 Boost 相关的互斥锁。
有人能告诉我这条消息的基本含义是什么,为什么会抛出“资源繁忙”异常?Blackberry 10 上是否存在与异常相关的已知问题?
提前致谢!
经过多次调试,一位同事终于解决了这个问题。
执行摘要
pthread_mutex_init () 在 55-65 次boost::mutex构造函数调用后抛出异常,因为应用程序级派生类对象(具有 boost::mutex 作为成员变量)没有完全析构,因为基类析构函数是非-虚拟的。这导致 boost::mutex-s 的数量增加,直到抛出互斥体异常。当正确调用派生类的析构函数时,不再抛出互斥异常。
沿途收集的相关/有趣的事实
(1) 一个早期的理论被提出,系统中有太多的互斥锁,并且应用程序超出了允许的最大同步对象数量的一些未知限制(尽管 QNX 文档明确指出此类对象的数量是无限的)。为了测试这一点,我们修改了boost::mutex类:
class mutex
{
private:
. . .
public:
mutex()
{
. . .
}
~mutex()
{
. . .
}
}
Run Code Online (Sandbox Code Playgroud)
到:
class mutex
{
private:
static int _nCount;
public:
mutex()
{
++_nCount;
. . .
}
~mutex()
{
. . .
--_nCount;
}
static int getCount ()
{
return _nCount;
}
. . .
}
Run Code Online (Sandbox Code Playgroud)
请注意,对 _nCount 变量的访问不是同步的(为此我们需要一个互斥对象!),但是从应用程序调用调试boost::mutex::getCount()函数让我们确信互斥的数量是异常时低(平均 55-65 个活动互斥体)。
这种通过添加静态访问函数在最低级别监视对象(例如,Boost 中的互斥锁)的技术是调试棘手问题时需要考虑的好工具。
(2) 我们偶尔会收到 ENOMEM 异常,表示内存问题(“系统无法分配创建互斥锁所需的资源”)。
(3)三个月前发布的 FreeBSD 站点与我们的症状非常相似:
我遇到了似乎无法解决的麻烦。我的程序可重复地创建和销毁互斥锁(并且,显然,在两者之间使用它们)。在创建第 60 个锁时,我总是得到 ENOMEM。我有空闲内存,很多。所有锁都被正确释放。
不幸的是,该线程并没有为我们指明建设性的方向。
(4) 当仔细研究应用程序的代码时,发现一个派生对象的基类析构函数是非虚拟的,从而泄漏了一些内存,从而取得了突破。使基类析构函数虚拟修复了内存泄漏并解决了互斥异常。
(5) 即使在将基类的析构函数设为虚拟之后,我们发现在使用 QNX® Momentics Tool Suite 为 Blackberry 10 编译时,派生类的析构函数并未被调用。我们通过将基础析构函数和派生析构函数都指定为 virtual来“破解”这个问题。只有这样,派生的析构函数才被调用。这可能表明 QNX 编译器对 C++ 规范的实现存在错误,该规范明确指出虚拟性会传播到派生类(工作草案,C++ 编程语言标准(2012 年),第 250 页,脚注 9)。
编辑:请参阅此 Stack Overflow 帖子,了解 QNX 放弃有关虚拟析构函数的另一个示例。
| 归档时间: |
|
| 查看次数: |
3818 次 |
| 最近记录: |