共享库中的内部异常终止最终用户应用程序

时间:2013-08-02 11:24:38

标签: c++ exception ubuntu g++

我正在构建一个内部使用Boost.thread的共享库。因此,Boost.system也被使用,因为Boost.thread依赖于此。我的共享库导出了一个C接口,所以我想隐藏最终用户的所有内部异常处理和线程使用等。可以说它应该是一个黑盒子。但是,当我链接到客户端应用程序时,程序运行正常 - 只要是时候通过调用库函数来停止处理我得到:

在抛出'boost :: thread_interrupted'

的实例后终止调用

我在库中内部捕获此异常,因此我不知道为什么它实际上没有被捕获。最终用户的程序无意以任何方式了解或处理Boost异常。在构建共享库时,我对Boost.thread和Boost.system都使用静态链接,因此外部世界从不打算看到它们。我在Ubuntu 12上的GCC 4.7上。在Windows上,我没有这样的问题(MSVC或MinGw都没有)。

(编辑)

我正在编辑问题,以显示根据评论中的请求重现问题的简约示例。

首先是testlib.cpp和testlib.h的代码。

testlib.cpp:

#include <boost/thread/thread.hpp>

void thread_func()
{
while(1)
{
boost::this_thread::interruption_point();
}
}

void do_processing()
{
// Start a thread that will execute the function above.
boost::thread worker(thread_func);

// We assume the thread started properly for the purposes of this example.

// Now let's interrupt the thread.
worker.interrupt();

// And now let's wait for it to finish.
worker.join();
}

现在testlib.h:

#ifndef TESTLIB_H
#define TESTLIB_H

void 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 -lboost_thread -lboost_system -lpthread -O3

然后,我有一个简单的客户端程序的代码,如下所示:

#include "testlib.h"
#include <cstdio>

int main()
{
do_processing();
printf("Execution completed properly.\n");
return 0;
}

我按如下方式构建客户端:

g ++ -DNDEBUG -I / usr / boost_1_54_0 -L ./-Wall -o client client.cpp -ltestlib -O3

当我运行客户端时,我得到:

在抛出'boost :: thread_interrupted'实例后终止调用 中止(核心倾销)

我没有明确地捕获线程中断异常,但根据Boost文档,Boost.thread会这样做并仅终止给定的线程。我尝试从thread_func函数中明确捕获异常,但这没有任何区别。

(编辑结束)

(编辑2)

值得注意的是,即使启用了-fexceptions,问题仍然存在。此外,我试图抛出并捕获一个异常,该异常在与捕获和抛出它的代码相同的转换单元中定义,没有任何改进。简而言之,即使我确实有捕获它们的处理程序,所有异常似乎在共享库中仍未被捕获。当我将客户端文件和testlib文件编译为单个程序的一部分时,也就是说不将testlib放入共享库中,一切都按预期工作。

(编辑结束2)

任何提示?

3 个答案:

答案 0 :(得分:1)

我终于明白了。如果指定了-shared,则不应指定-static标志。我的信念是,它只是告诉链接器更喜欢它链接的库的静态版本,而是使生成的动态库不适合动态链接,这有点讽刺。但它确实如此。删除-static解决了我所有的问题,我能够在动态库中静态链接Boost,完全处理异常。

答案 1 :(得分:0)

也许this

  

如果你有一个库L抛出E,那么L和   应用程序必须链接到X,包含的库   E的定义。

尝试将可执行文件与boost相关联。

答案 2 :(得分:0)

一个共享库本身包含静态链接库并不是一个好主意,我认为这种情况在GNU工具链中得不到很好的支持。

我认为您的特定问题来自选项-static-libgcc,但我无法使用您的选项在我的机器中编译它。并非静态地将libpthread.so声音与-pthread声音联系起来也不是......如果主要可执行文件想要创建自己的线程会发生什么?它会用libboost_thread.so.1.54.0编译吗?如果是,则将链接两次线程函数;如果不是,它将具有函数,但不具有预编译器宏和线程安全库函数。

我的建议是不要静态编译你的库,这不是Linux方式。

实际上,这不应该是一个真正的问题,即使您不想依赖boost的分发版本:针对共享的boost库编译您的程序并部署所有这些文件(libboost_system.so.1.54.0,{{ 1}}和libtestlib.so)到同一目录。然后使用LD_LIBRARY_PATH=<path-to-so-files>运行您的程序。由于客户端不打算直接使用boost,因此它不需要boost头,也不需要在编译器命令中链接它们。你仍然有你的黑匣子,但现在它由3 * so文件组成,而不仅仅是1。