首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Boost线程:在IOS中,thread_info对象在线程完成执行之前就被销毁了

Boost线程:在IOS中,thread_info对象在线程完成执行之前就被销毁了
EN

Stack Overflow用户
提问于 2013-02-05 02:10:17
回答 2查看 2.6K关注 0票数 8

我们的项目在几个平台上使用了一些boost 1.48库,包括Windows、Mac、Android和IOS。当使用IOS时,我们能够一致地使项目的IOS版本崩溃(不是平凡但可靠的),并且从我们的调查中我们看到,当线程仍在运行时,~thread_data_base在线程的thread_info上被调用。

这似乎是由于智能指针达到零计数的结果,即使它显然仍然在创建它并在线程中运行所请求函数的thread_proxy函数的作用域中。这似乎在各种情况下都会发生-尽管有一些常见的变体,但调用堆栈在崩溃之间并不相同。

这通常需要运行创建数百个线程的代码,尽管同时运行的线程永远不会超过30个。我“很幸运”,在跑步的早期就得到了它,但这是很少见的。我创建了析构函数的一个版本,它实际捕获了代码:

在libs/thread/src/pthread/thread.cpp中:

代码语言:javascript
复制
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“不同,这真的很奇怪。

另外,当我第一次编写该版本的代码时,我写道:

代码语言:javascript
复制
if (((void*)thread_info) == ((void*)this)) 

在运行时,我得到了一些非常奇怪的异常,告诉我关于虚拟函数表或类似的东西-我不记得了。我认为它试图为这个对象类型调用"==“,并对此不满意,所以我重写了上面的代码,将转换为void *作为单独的代码行。这本身对我来说是非常可疑的。我不是那种急于指责编译器的人,但是...

我还应该注意到,当我们捕获到这种情况时,我们看到~shared_count的析构函数在Xcode源代码的堆栈上连续出现了两次。非常奇怪。我们试着看一下反汇编,但没能理解太多。

再说一次,这看起来总是shared_count的结果,而shared_ptr似乎拥有thread_info,过早地将其归零。

更新:似乎可以进入达到上述陷阱的情况,而不会造成任何伤害。自从修复了这个问题(见答案),我已经看到它发生了,但总是在thread_info->run()完成执行之后。还不了解how...but,它正在工作。

一些附加信息:

我应该注意到,来自Pete Goodliffe (并被其他人修改)的boost.sh通常用于编译IOS的boost,在标题中有以下注释:

代码语言:javascript
复制
: ${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

这暗示了在arm处理器中使用boost内部的替代实现,这似乎也直接解决了这个问题:spinlock_gcc_arm.hpp

boost 1.48附带的版本使用过时的arm组件。我从boost 1.52获取了更新版本,但我在编译它时遇到了问题。我得到以下错误:谓词指令必须在IT块中

我在这里找到了对此指令类似用法的引用:https://zeromq.jira.com/browse/LIBZMQ-414

我能够使用相同的想法,通过如下修改代码来编译1.52代码(我插入了适当的IT指令)

代码语言:javascript
复制
__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体系结构,这在我的环境中没有这样定义。在我简单地编辑了这个文件以便只剩下ARM7代码之后,编译器抱怨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‘展开

代码语言:javascript
复制
# define BOOST_SP_ARM_BARRIER "dmb"

有什么想法吗?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2013-02-07 04:53:36

我想通了。事实证明,我在问题中提到的boost.sh脚本选择了错误的boost标志来解决这个问题-而不是BOOST_SP_USE_PTHREADS (以及与之相关的另一个标志,BOOST_AC_USE_PTHREADS),事实证明在IOS上需要的是BOOST_SP_USE_SPINLOCK。这最终给出了与问题中提到的std::thread问题中使用的解决方案几乎相同的解决方案。

如果你正在编译任何使用ARM7的现代IOS设备,但使用的是旧的boost (我们使用的是1.48),你需要从较新的boost (如1.52)复制文件spinlock_gcc_arm.hpp。对于不同的arm架构,该文件是#ifdef'd,但我不清楚它正在寻找的定义是在IOS编译环境中使用脚本定义的。因此,你可以编辑文件(暴力但有效),或者花些时间弄清楚如何使其整洁和正确。

在任何情况下,您都可能需要在问题"it ne;\n“中插入我所做的额外汇编指令:”it ne;\n“我还没有回去查看是否可以删除它,因为我的编译环境有问题。

然而,我们还没有完成。boost中用于此选项的代码包括(如讨论的) ARM汇编语言指令。ARM芯片支持两个指令集,这两个指令集不能在一个给定的模块中混合(不确定范围,但显然在编译时逐个文件是一个可接受的粒度)。boost中用于此锁定的指令包括非Thumb指令,但IOS默认使用Thumb指令集。boost代码知道指令集问题,会检查您是否启用了arm,但没有启用thumb,但在IOS中,默认情况下,thumb是打开的。

让编译器生成非thumb ARM代码取决于您在IOS中使用的编译器-Apple的LLVM还是LLVM GCC。不推荐使用GCC,使用XCode默认使用苹果的LLVM。

对于默认的Clang + Apple LLVM4.1,您需要使用-mno-thumb标志进行编译。此外,IOS应用程序中使用智能指针的boost的任何部分的任何文件都必须使用-mno-thumb进行编译。

要像这样编译boost,我认为您只需将-mno-thumb添加到脚本中的EXTRA_CPP_FLAGS即可。(我在实验时直接修改了user-config.jam,还没有回去清理。)

对于您的应用程序,您需要在Xcode中选择您的目标,然后进入构建阶段选项卡,并在那里选择编译源。在这里,您可以选择添加编译标志,因此对于每个相关文件(包括boost),请添加-mno-thumb标志。您也可以直接在project.pbxproj中执行此操作,其中每个文件都有

代码语言:javascript
复制
settings = { COMPILER_FLAGS = ""; };   

您只需将其更改为

代码语言:javascript
复制
settings = { COMPILER_FLAGS = "-mno-thumb"; }; 

但还有更多的东西。您还必须修改tools/build/v2/tools目录中的darwin.jam文件。在boost 1.48中,有一段代码说:

代码语言:javascript
复制
    case arm :
    {
        options = -arch armv6;
    }

必须将其修改为

代码语言:javascript
复制
    case arm :
    {
        options = -arch armv7 ;
    }        

最后,在boost.sh脚本的writeBjamUserConfig()函数中,您应该删除对-arch armv6的引用。

如果有人知道如何更全面和更干净地做这件事,我相信我们都会受益。就目前而言,这就是我所要做的,我希望这能对其他IOS boost线程用户有所帮助。我希望boost.sh IOS脚本的各种变体都能更新。我计划稍后在这个答案中添加更多的链接。

更新:提供了一篇很好的文章,描述了处理器级别的问题,

查看此处:http://preshing.com/20121019/this-is-why-they-call-it-a-weakly-ordered-cpu

享受吧!

票数 8
EN

Stack Overflow用户

发布于 2013-08-17 16:12:04

我在iOS平台上使用boost.asio,boost.thread,boost.smart_ptr等,应用程序在发布模式下运行时总是崩溃,这会抛出信号。崩溃调用堆栈是:

代码语言:javascript
复制
__stack_chk_fail
boost::asio::detail::completion_handle
boost::asio::detail::task_ios_service_operation::complete
boost::asio::detail::task_io_service::do_run_one
boost::asio::detail::task_ios_service::run
boost::asio::io_service::run
![when create a asio work with creating new thread and io_service][1]

在尝试解决这个问题时,我找到了以下文章:

代码语言:javascript
复制
[boost-thread-threads-not-starting-on-the-iphone-ipad-in-release-build][2]

[The issue of spin_lock and thumb on iOS][3]

然后,我尝试将-mno-thumb添加到我的项目编译标志中,在发布模式下出现的问题就消失了。

然而,一个新的bug出现了:EXC_ARM_DA_ALIGN,,它在我试图将网络数据转换为主机端的时候崩溃了。

正如本文所说,ARM指令严格要求内存数据必须对齐。

遵循文章[Exc_arm_da_align][5],我通过使用memcpy进行数据转换来修复它,而不是直接从指针转换。

代码语言:javascript
复制
  [1]: http://i.stack.imgur.com/3ijF4.png
  [2]: http://stackoverflow.com/questions/4201262/boost-thread-threads-not-starting-on-the-iphone-ipad-in-release-builds/4245821#4245821
  [3]: http://groups.google.com/group/boost-list/browse_thread/thread/7dc1e80659182ab3
  [4]: https://brewx.qualcomm.com/bws/content/gi/common/appseng/en/knowledgebase/docs/kb95.html
  [5]: http://www.cnblogs.com/unionfind/archive/2013/02/25/2932262.html
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/14692802

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档