我们的项目在多个平台上使用了一些 boost 1.48 库,包括 Windows、Mac、Android 和 IOS。在使用 IOS 时,我们能够始终如一地让项目的 IOS 版本崩溃(不平凡但可靠),并且从我们的调查中我们看到 ~thread_data_base 在线程仍在运行时在线程的 thread_info 上被调用。
这似乎是由于智能指针达到零计数而发生的,即使它显然仍在创建它并在线程中运行请求的函数的 thread_proxy 函数的范围内。这似乎发生在各种情况下 - 崩溃之间的调用堆栈并不相同,尽管有一些常见的变化。
需要明确的是 - 这通常需要运行创建数百个线程的代码,尽管同时运行的线程永远不会超过 30 个。我“很幸运”并且在跑步的早期也得到了它,但这种情况很少见。我创建了一个析构函数版本,它实际上捕获了代码:
在 libs/thread/src/pthread/thread.cpp 中:
thread_data_base::~thread_data_base()
{
boost::detail::thread_data_base* const thread_info=detail::get_current_thread_data();
void *void_thread_info = (void *) thread_info;
void *void_this = (void *) this;
// is somebody destructing the thread_data other than its own thread?
// (remember that its own which should no longer point to it anyway,
// because of the call to detail::set_current_thread_data(0) in thread_proxy)
if (void_thread_info) { // == void_this) {
__builtin_trap();
}
}
我应该注意到(从注释掉的代码中可以看出)我之前检查过 void_thread_info == void_this 因为我只检查线程的当前 thread_info 正在杀死自己的情况。我还看到 get_current_thread_data 返回的值非零且与“this”不同的情况,这真的很奇怪。
同样,当我第一次编写该版本的代码时,我写道:
if (((void*)thread_info) == ((void*)this))
在运行时,我遇到了一些非常奇怪的异常,说我关于虚拟函数表或类似的东西 - 我不记得了。我决定它试图为这个对象类型调用“==”并且对此不满意,所以我如上所述重写,将转换为 void * 作为单独的代码行。这本身对我来说很可疑。我不是一个急于指责编译器的人,但是......
我还应该注意,当我们确实捕捉到这种情况发生的陷阱时,我们看到 ~shared_count 的析构函数在 Xcode 源代码的堆栈中连续出现两次。很奇怪。我们试图查看拆解,但无法从中得到太多。
再次 - 看起来这始终是 shared_count 的结果,它似乎由拥有 thread_info 的 shared_ptr 拥有,过早地达到零。
更新:似乎有可能进入达到上述陷阱的情况而不会造成任何伤害。自从解决了这个问题(见答案)我已经看到它发生了,但总是在 thread_info->run() 完成执行之后。还不明白如何......但它正在工作。
一些附加信息:
我应该注意到,通常用于为 IOS 编译 boost 的来自 Pete Goodliffe(并被其他人修改)的 boost.sh 在标题中具有以下注释:
: ${EXTRA_CPPFLAGS:="-DBOOST_AC_USE_PTHREADS -DBOOST_SP_USE_PTHREADS"}
# The EXTRA_CPPFLAGS definition works around a thread race issue in
# shared_ptr. I encountered this historically and have not verified that
# the fix is no longer required. Without using the posix thread primitives
# an invalid compare-and-swap ARM instruction (non-thread-safe) was used for the
# shared_ptr use count causing nasty and subtle bugs.
#
# Should perhaps also consider/use instead: -BOOST_SP_USE_PTHREADS
我使用这些标志,但无济于事。
我发现以下内容非常诱人 - 看起来他们在std::thread:
http://llvm.org/bugs/show_bug.cgi?format=multiple&id=12730
这暗示了在 boost 中为 arm 处理器使用替代实现,这似乎也直接解决了这个问题:
spinlock_gcc_arm.hpp
boost 1.48 包含的版本使用过时的臂组件。我从 boost 1.52 获取了更新版本,但我在编译它时遇到了问题。我收到以下错误:谓词指令必须在 IT 块中
我在这里找到了对该指令的类似用法的参考: https ://zeromq.jira.com/browse/LIBZMQ-414
通过如下修改代码,我能够使用相同的想法来编译 1.52 代码(我插入了适当的 IT 指令)
__asm__ __volatile__(
"ldrex %0, [%2]; \n"
"cmp %0, %1; \n"
"it ne; \n"
"strexne %0, %1, [%2]; \n"
BOOST_SP_ARM_BARRIER :
"=&r"( r ): // outputs
"r"( 1 ), "r"( &v_ ): // inputs
"memory", "cc" );
但无论如何,这个文件中有 ifdefs 用于查找 arm 架构,但在我的环境中没有以这种方式定义。在我简单地编辑文件以便只剩下 ARM 7 代码之后,编译器抱怨 BOOST_SP_ARM_BARRIER 的定义:
在 ./boost/smart_ptr/detail/spinlock.hpp:35 包含的文件中:./boost/smart_ptr/detail/spinlock_gcc_arm.hpp:39:13: 错误:指令需要当前未启用的 CPU 功能 BOOST_SP_ARM_BARRIER : ^ ./boost /smart_ptr/detail/spinlock_gcc_arm.hpp:13:32:注意:从宏 'BOOST_SP_ARM_BARRIER' 扩展
# define BOOST_SP_ARM_BARRIER "dmb"
有任何想法吗??