共享库中的内部异常终止最终用户应用程序
Internal exceptions in shared library terminate end user application
我正在构建一个内部使用Boost.thread的共享库。因此,Boost.system也被使用,因为Boost.thread依赖于它。我的共享库导出了一个C接口,所以我想向最终用户隐藏我所有的内部异常处理和线程使用等。可以这么说,它应该是一个黑盒子。然而,当我链接到客户端应用程序时,当程序运行良好时——只要到了通过调用库函数来停止处理的时候,我就会得到:
在抛出"boost::thread_interrupted"的实例后调用terminate
我在库内部捕获了这个异常,所以我不知道为什么它实际上没有被捕获。最终用户的程序并不意味着以任何方式了解或处理Boost异常。在构建共享库时,我对Boost.thread和Boost.system都使用静态链接,所以外界永远不会看到它们。我在Ubuntu 12上使用GCC 4.7。在Windows上,我没有这样的问题(MSVC和MinGw都没有)。
(编辑)
根据评论中的要求,我正在编辑这个问题,以展示一个重现问题的极简主义例子。
这里首先是testlib.cpp和testlib.h的代码。
testlib.cpp:
#包括<boost/thread/thread.hpp>void thread_func(){而(1){boost::this_thread::interruption_point();}}作废do_processing(){//启动一个线程来执行上面的函数。boost::线程工作者(thread_func);//出于本例的目的,我们假设线程已正确启动。//现在让我们中断线程。worker.interrupt();//现在让我们等待它结束。worker.join();}
现在是testlib.h:
#ifndef TESTLIB_H#定义TESTLIB_Hvoid do_processing();#endif
我用以下命令将其构建到一个共享库中:
g++-static libgcc-static-s-DNDEBUG-I/usr/boost_1_54_0-L/usr/boost_1 _54_0/stage/lib-Wall-shared-fPIC-o libtestlib.so testlib.cpp-lbost_thread-lbostrongystem-lpthread-O3
然后,我有了一个琐碎客户端程序的代码,如下所示:
#包括"testlib.h"#包括<cstdio>int main(){do_processing();printf("执行已正确完成。\n");返回0;}
我构建客户端如下:
g++-DNDEBUG-I/usr/boost_1_54_0-L./-Wall-o客户端.cpp-ltestlib-O3
当我运行客户端时,我得到:
在抛出"boost::thread_interrupted"的实例后调用terminate
中止(堆芯转储)
我没有明确地捕捉线程中断异常,但根据Boost文档,Boost.thread会这样做,并仅终止给定的线程。我尝试从thread_func函数中显式捕获异常,但没有什么区别。
(编辑结束)
(编辑2)
值得注意的是,即使启用了-fexceptions,问题仍然存在。此外,我尝试抛出并捕获一个异常,该异常与捕获并抛出它的代码在同一翻译单元中定义,但没有任何改进。简而言之,在共享库中,所有异常似乎都是未捕获的,尽管我确实为它们提供了捕获处理程序。当我将客户端文件和testlib文件作为单个程序的一部分进行编译时,也就是说,在不将testlib制作成共享库的情况下,一切都能按预期进行。
(第2版结束)
有什么建议吗?
我终于弄明白了。当指定-shared时,永远不应该指定-static标志。我认为它只是告诉链接器更喜欢它链接的库的静态版本,但它却使生成的动态库不适合动态链接,这有点讽刺。但事实就是这样。删除静态解决了我所有的问题,我能够在我的动态库中很好地静态链接Boost,它完美地处理了异常。
也许是这样?
如果你有一个抛出E的库L,那么L和应用程序A必须链接到X,该库包含E.的定义
也尝试将可执行文件链接到boost。
一个本身包括静态链接库的共享库不是一个好主意,我认为GNU工具链中不太支持这种场景。
我认为您的特定问题源于选项-static-libgcc
,但我无法使用您的选项在我的机器中编译它。静态链接到libpthread.so
听起来也不是一个好主意。。。如果主可执行文件想要创建自己的线程,会发生什么?它会用-pthread
编译吗?如果是,那么您将链接两次线程函数;如果没有,它将具有函数,但没有预编译器宏或线程安全库函数。
我的建议是不要静态编译库,这不是Linux的方式。
事实上,这应该不是一个真正的问题,即使你不想依赖boost的分发版本:根据共享的boost库编译你的程序,并将所有这些文件(libboost_thread.so.1.54.0
、libboost_system.so.1.54.0
和libtestlib.so
)部署到同一目录中。然后使用LD_LIBRARY_PATH=<path-to-so-files>
运行您的程序。由于客户端不打算直接使用boost,因此它不需要boost头,也不需要在编译器命令中链接它们。你仍然有你的黑盒,但现在它是由3*so文件组成的,而不是只有1个。
- 我的web应用程序的用户需要在浏览器上手动启用本机客户端吗
- 微筛选器从用户模式应用程序接收常量值
- 指定在用户固定我的应用程序时用于运行应用程序的命令参数
- 如何检查用户是否已打开应用程序
- 无论如何,是否可以确定MFC应用程序是通过PC重新启动或用户单击应用程序快捷方式开始的
- 内核模块或用户空间应用程序
- 如何从 Windows 上的服务在未登录用户的桌面上启动应用程序
- 如何将用户代码合并到我自己的应用程序中?
- 如果使用不同的用户凭据启动该应用程序,则CERTFINDCERTIFIFIFICATESTORE将无法找到证书
- 拥有用于QT应用程序的Web用户界面的最佳方法
- 加密用户数据,而不会丢失安卓应用程序中的登录用户
- 是否可以报告用户在 Android 应用程序中单击了哪些按钮
- 我可以在形式的应用程序中查询用户交互事件
- 如何在具有 WppEnabled 标志的用户模式应用程序中使用 WPP 跟踪
- 从用户应用程序访问环0模式(以及Borland允许这样做的原因)
- 从 mfc 应用程序点击网络服务,并希望从网络服务登录方法读取用户代码返回
- 如何从另一个登录用户启动登录用户内部的应用程序
- 共享库中的内部异常终止最终用户应用程序
- 如何实现将数据从用户应用程序传输到类内部存储器的类方法
- 如何从用户应用程序发送自定义消息到系统应用程序