【问题标题】:What can cause an exception 16: "mutex: Resource busy" to be thrown (using Boost / BB10)?什么会导致异常 16: "mutex: Resource busy" 被抛出(使用 Boost / BB10)?
【发布时间】:2013-08-02 19:45:16
【问题描述】:

我已将一个用 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

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

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

提前致谢!

【问题讨论】:

  • io_service 将在各种平台内部使​​用互斥锁来完成多项任务。但是我对BB10并不熟悉。您可以附加一个调试器并在调用站点捕获异常吗? io_service 构造函数是否抛出异常?查看堆栈跟踪会很有用。
  • 到目前为止,我还没有成功进入 Boost 代码本身,但这绝对是目标的方法——敬请期待。
  • 这可能是boost/asio/detail/impl/posix_mutex.ipp,这是我能找到的唯一一个使用字符串"mutex" 抛出system_error 的地方。假设 BB10 是 posix,如果 mutex 已经初始化,pthread_mutex_init 可能会失败。堆栈跟踪将在这里提供帮助。
  • @SamMiller:+1 评论 reposix_mutex.ipp:我搜索了 Boost 源代码,但没有找到这条线索。你让我看到了“盔甲上的裂缝”——谢谢!

标签: c++ exception boost boost-asio blackberry-10


【解决方案1】:

一位同事经过多次调试终于解决了这个问题。

执行摘要

pthread_mutex_init () 在 55-65 次 boost::mutex 构造函数调用后抛出异常,因为具有 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) 当仔细研究应用程序的代码发现一个派生对象的基类析构函数是非虚拟的,从而泄漏了一些内存时,突破就来了。使基类析构函数 virtual 修复了内存泄漏并解决了互斥异常。

(5) 即使在将基类的析构函数设为虚拟之后,我们发现在使用 QNX® Momentics Tool Suite 为 Blackberry 10 进行编译时,派生类的析构函数并未被调用。我们通过将基本和派生析构函数都指定为虚拟来“破解”这个问题。只有这样派生的析构函数才会被调用。这可能表明 QNX 编译器的 C++ 规范实现中存在错误,该规范明确指出虚拟性传播到派生类 (Working Draft, Standard for Programming Language C++ (2012), page 250, footnote 9)。

编辑:请参阅this Stack Overflow post,了解 QNX 关于虚拟析构函数的另一个丢球示例。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-01-06
    • 1970-01-01
    • 2015-07-09
    • 1970-01-01
    • 1970-01-01
    • 2014-02-17
    • 2014-12-03
    • 1970-01-01
    相关资源
    最近更新 更多