5

我正在构建一个在内部使用 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 的代码。

测试库.cpp:

#include <boost/thread/thread.hpp>

无效线程函数()
{
而(1)
{
boost::this_thread::interruption_point();
}
}

无效 do_processing()
{
// 启动一个线程来执行上面的函数。
boost::thread worker(thread_func);

// 出于本示例的目的,我们假设线程正确启动。

// 现在让我们中断线程。
worker.interrupt();

// 现在让我们等待它完成。
worker.join();
}

现在 testlib.h:

#ifndef TESTLIB_H
#define TESTLIB_H

无效做处理();

#万一

我使用以下命令将其构建到共享库中:

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>

主函数()
{
做处理();
printf("执行正确完成。\n");
返回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 结束)

有小费吗?

4

3 回答 3

1

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

于 2013-08-15T21:15:31.830 回答
0

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

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

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

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

于 2013-08-10T00:15:57.917 回答
0

也许这个

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

也尝试将可执行文件与 boost 链接起来。

于 2013-08-05T18:10:53.323 回答