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

我正在构建一个内部使用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)

2 years ago

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

2 years ago

也许this

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

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

2 years ago

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

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

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

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