什么可能导致异常16:“互斥:资源忙”被抛出(使用Boost / BB10)?

时间:2013-08-01 18:20:22

标签: c++ exception boost 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;
}

跟踪日志行是:

18:37:04 ( 149077264) [error] Boost exception (16 / "mutex: Resource busy") caught in HandleQueueOperation

在上面的“start”和“end”注释之间抛出异常,其中定义了boost :: asio :: io_service对象。我搜索了StackOverflow,谷歌等与“互斥:资源忙”相关的任何内容,但一无所获。我的代码此时没有访问任何应用程序级别的互斥锁,因此我假设所引用的互斥锁是与Boost相关的互斥锁。

有人可以告诉我这条消息的基本含义,以及为什么会抛出“资源忙”异常? Blackberry 10上是否存在与该例外相关的已知问题?

提前致谢!

1 个答案:

答案 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