我已经将一个用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;
}
跟踪日志行是:
18:37:04 ( 149077264) [error] Boost exception (16 / "mutex: Resource busy") caught in HandleQueueOperation
在上面的“start”和“end”注释之间抛出异常,其中定义了boost :: asio :: io_service对象。我搜索了StackOverflow,谷歌等与“互斥:资源忙”相关的任何内容,但一无所获。我的代码此时没有访问任何应用程序级别的互斥锁,因此我假设所引用的互斥锁是与Boost相关的互斥锁。
有人可以告诉我这条消息的基本含义,以及为什么会抛出“资源忙”异常? Blackberry 10上是否存在与该例外相关的已知问题?
提前致谢!
答案 0 :(得分:4)
经过多次调试,一位同事终于解决了这个问题。
执行摘要
在55-65 boost :: mutex 构造函数调用之后,pthread_mutex_init()抛出了异常,因为具有boost :: mutex作为成员变量的应用程序级派生类对象是没有完全破坏,因为基类析构函数是非虚拟的。这导致boost :: mutex-s的数量上升,直到抛出互斥锁异常。当正确调用派生类的析构函数时,不再抛出互斥锁异常。
沿途收集相关/有趣的事实
(1)提出了一个早期的理论,即系统中存在太多的互斥体,并且应用程序对允许的最大同步对象数量有一些未知限制(尽管QNX文档清楚地说明了这些对象的数量是无限)。为了测试这个,我们修改了 boost :: mutex 类:
class mutex
{
private:
. . .
public:
mutex()
{
. . .
}
~mutex()
{
. . .
}
}
为:
class mutex
{
private:
static int _nCount;
public:
mutex()
{
++_nCount;
. . .
}
~mutex()
{
. . .
--_nCount;
}
static int getCount ()
{
return _nCount;
}
. . .
}
请注意,对_nCount变量的访问不同步(我们需要一个互斥对象!),但是从应用程序调用调试 boost :: mutex :: getCount()函数让我们相信异常时互斥量的数量很少(平均55-65个活跃的互斥量)。
这种通过添加静态访问函数来监视最低级别对象(例如,Boost中的互斥体)的技术是调试粘性问题时需要考虑的好工具。
(2)我们偶尔会收到ENOMEM异常,表示存在内存问题(“系统无法分配创建互斥锁所需的资源”)。
(3)A FreeBSD site posting from three months ago与我们的症状非常相似:
我遇到了麻烦,我似乎无法解决。我的节目 重复地创建和销毁互斥体(显然,使用它们 之间)。创造了第60个锁,我总是得到ENOMEM。我有 免费记忆,很多。所有锁都能正确释放。
不幸的是,该主题没有指出我们的建设性方向。
(4)当仔细研究应用程序的代码时,发现了一个派生对象,其基类析构函数是非虚拟的,从而泄漏了一些内存。使基类析构函数虚拟修复了内存泄漏并解决了互斥异常。
(5)即使在使基类的析构函数为virtual之后,我们发现在使用QNX®MomenticsTool Suite编译Blackberry 10时没有调用派生类的析构函数。我们通过将基本和派生析构函数指定为虚拟来“破解”此问题。只有这样才能调用派生的析构函数。这可能表明QNX编译器的C ++规范实现中存在错误,该错误清楚地表明虚拟传播到派生类(Working Draft, Standard for Programming Language C++ (2012), page 250, footnote 9)。
编辑:有关QNX关于虚拟析构函数的另一个例子,请参阅this Stack Overflow post。