升压线程:在IOS,的thread_info对象被线程完成执行前销毁 [英] Boost threads: in IOS, thread_info object is being destructed before the thread finishes executing

查看:432
本文介绍了升压线程:在IOS,的thread_info对象被线程完成执行前销毁的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们的项目采用了一些提升1.48库在多种平台上,包括Windows,Mac,Android和IOS。
我们能够始终如一地获得该项目的IOS版本使用IOS时崩溃(nontrivially但可靠),和
从我们的调查,我们看到,〜thread_data_base正在呼吁线程的thread_info,而它的线程仍在运行。

Our project uses a few boost 1.48 libraries on several platforms, including Windows, Mac, Android, and IOS. We are able to consistently get the IOS version of the project to crash (nontrivially but reliably) when using IOS, and from our investigation we see that ~thread_data_base is being called on the thread's thread_info while its thread is still running.

此似乎发生作为智能指针达到零计数的结果,即使它是显然仍
在创造它,并运行在该线程所请求的功能的thread_proxy功能范围。
这似乎在各种情况下发生 - 调用栈是崩溃之间不相同,虽然有几个
变化这些都是常见的。

This seems to happen as a result of the smart pointer reaching a zero count, even though it is obviously still in scope in the thread_proxy function which creates it and runs the requested function in the thread. This seems to happen in various cases - the call stack is not identical between crashes, though there are a few variations which are common.

只是要清楚 - 这通常需要运行code这是创造数百个线程,虽然有
从不超过约30同时运行。我有幸运,并在得到它非常非常早
也跑,但这是罕见的。
我创建了一个版本,它实际上抓住了code当场析构函数:

Just to be clear - this often requires running code which is creating hundreds of threads, though there are never more than about 30 running simultaneously. I have "been lucky" and got it very very early in the run also, but that's rare. I created a version of the destructor which actually catches the code red-handed:

在库/线程/ src目录/的pthread / thread.cpp:

in 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();
   }
 }

我要指出,(从注释掉code看到)我已经previously检查看到void_thread_info == void_this因为我
只检查其中线程的当前的thread_info被杀死本身的情况。
我也看到情况下,由get_current_thread_data返回的值是非零和
从本,这是很奇怪的不同。

I should note that (as seen from the commented-out code) I had previously checked to see that void_thread_info == void_this because I was only checking for the case where the thread's current thread_info was killing itself. I have also seen cases where the value returned by get_current_thread_data is non-zero and different from "this", which is really weird.

此外,当我第一次写了code的版本中,我写道:

Also when I first wrote that version of the code, I wrote:

if (((void*)thread_info) == ((void*)this)) 

和在运行时,我得到了一些非常奇怪的例外是说我一些关于虚函数表
或者类似的东西 - 我不记得了。我决定,这是试图调用==这个对象类型
和不高兴这一说法,所以我如上改写,把转换为void *作为单独的
code线。这本身是相当可疑的我。我不是一个跑冲上去责怪编译器,但...

and at run-time I got some very weird exception that said I something about a virtual function table or something like that - I don't remember. I decided that it was trying to call "==" for this object type and was unhappy with that, so I rewrote as above, putting the conversions to void * as separate lines of code. That in itself is quite suspicious to me. I am not one to run to rush to blame compilers, but...

我也应该注意,当我们没有抓住这个发生的陷阱,我们看到的析构函数
〜SHARED_COUNT连续出现两次X code源代码的堆栈。非常doubleweird。
我们想看看拆卸,但不能使离谱了吧。

I should also note that when we did catch this happening the trap, we saw the destructor for ~shared_count appear twice consecutively on the stack in Xcode source. Very doubleweird. We tried to look at the disassembly, but couldn't make much out of it.

再次 - 它看起来像这样总是这似乎为所拥有的SHARED_COUNT的结果
该公司拥有的thread_info达到零太早shared_ptr的。

Again - it looks like this is always a result of the shared_count which seems to be owned by the shared_ptr which owns the thread_info reaching zero too early.

更新:它似乎是可能的进入未经情况做任何损害达到上述捕集的情况。由于固定问题(见回答)我看到了这一点,但总是经过thread_info->的run()执行完毕。还不明白怎么...但它的工作。

Update: it seems that it is possible to get into situations which reach the above trap without the situation doing any harm. Since fixing the issue (see answer) I have seen it happen, but always after thread_info->run() has finished executing. Don't yet understand how...but it's working.

一些额外的信息:

我要指出,从皮特Goodliffe一种常用编译提振了IOS的boost.sh(被他人修改)
有以下注意事项在标题:

I should note that the boost.sh from Pete Goodliffe (and modified by others) that is commonly used to compile boost for IOS has the following note in the header:

: ${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

我使用这些标志,但无济于事。

I use those flags, but to no avail.

我发现这是非常诱人的下面 - 它看起来像他们曾在的std ::线程同样的问题:

I found the following which is very tantalizing - it looks like they had the same issue in std::thread:

http://llvm.org/bugs/show_bug.cgi?格式=多和ID = 12730

这是联想内部使用的提振似乎也可以直接解决这个问题ARM处理器的替代实现:
spinlock_gcc_arm.hpp

That was suggestive of using an alternate implementation inside boost for arm processors which seems also to directly address this issue: spinlock_gcc_arm.hpp

附带提升1.48版本使用了过时的臂组件。
我把更新后的版本从1.52提升,但我无法编译它。
我得到以下错误:
predicated指令必须在IT块

The version included with boost 1.48 uses outdated arm assembly. I took the updated version from boost 1.52, but I'm having trouble compiling it. I get the following error: predicated instructions must be in IT block

我发现什么看起来是一个类似用途这里该指令的参考:
https://zeromq.jira.com/browse/LIBZMQ-414

I found a reference to what looks to be a similar use of this instruction here: https://zeromq.jira.com/browse/LIBZMQ-414

我能够用同样的想法,以获得1.52 code通过修改编译
在code如下(我插入一个合适的IT指令)

I was able to use the same idea to get the 1.52 code to compile by modifying the code as follows (I inserted an appropriate IT instruction)

__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" );

但是,在任何情况下,存在在此文件用于寻找该臂结构,这是没有定义在我的环境那样的ifdef。之后我只是编辑的文件,这样只有ARM 7 code
被留下,编译器抱怨BOOST_SP_ARM_BARRIER的定义:

But in any case, there are ifdefs in this file which look for the arm architecture, which is not defined that way in my environment. After I simply edited the file so that only ARM 7 code was left, the compiler complains about the definition of 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扩大

In file included from ./boost/smart_ptr/detail/spinlock.hpp:35: ./boost/smart_ptr/detail/spinlock_gcc_arm.hpp:39:13: error: instruction requires a CPU feature not currently enabled BOOST_SP_ARM_BARRIER : ^ ./boost/smart_ptr/detail/spinlock_gcc_arm.hpp:13:32: note: expanded from macro 'BOOST_SP_ARM_BARRIER'

# define BOOST_SP_ARM_BARRIER "dmb"

任何想法??

推荐答案

想通了这一点。事实证明,我的问题提boost.sh脚本选择了不正确的提振标志来解决这个问题 - 而不是 BOOST_SP_USE_PTHREADS (和它的另一标志出现, BOOST_AC_USE_PTHREADS )事实证明,有必要对IOS的是 BOOST_SP_USE_SPINLOCK 。这最终让pretty多在问题中提到的的std ::线程问题所用的相同的解决方案。

Figured this out. It turns out that the boost.sh script that I mention in the question chose the incorrect boost flag to address this problem - instead of BOOST_SP_USE_PTHREADS (and the other flag there with it, BOOST_AC_USE_PTHREADS) it turns out that what is needed on IOS is BOOST_SP_USE_SPINLOCK. This ends up giving pretty much the identical solution used in the std::thread issue referred to in the question.

如果要编译支持其采用ARM 7任何现代的iOS设备,但使用的是老式提升(我们使用的是1.48),你需要将文件从spinlock_gcc_arm.hpp更近的刺激(如1.52)复制。这个文件是不同的ARM体系结构#ifdef'd,但目前尚不清楚对我来说,定义它正在寻找使用脚本中的IOS编译环境中定义。所以,你可以编辑文件(暴力但有效)或投资一些时间来弄清楚如何使这种整齐和正确的。

If you are compiling for any modern IOS device which uses ARM 7, but using an older boost (we are using 1.48), you need to copy the file spinlock_gcc_arm.hpp from a more recent boost (like 1.52). That file is #ifdef'd for the different arm architectures, but it is not clear to me that the defines it is looking for are defined in the IOS compile environment using the script. So you can either edit the file (violent but effective) or invest some time to figure out how to make this tidy and correct.

在任何情况下,你可能需要插入,我在这个问题上面做了额外的汇编指令:
 它NE; \\ n
我还没有去回看我能不能现在我有我的编译环境下工作的问题删除。

In any case, you may need to insert the extra assembly instruction that I did above in the question: "it ne; \n" I have not yet gone back to see if I can delete that now that I have my compile environment working problem.

不过,我们还没有完成。在提升使用此选项的code中,作为讨论的,ARM汇编语言指令。 ARM的芯片支持两个指令集不能给定的模块中混合(不知道的范围,但显然文件是文件编辑时可以接受的粒度)。升压用于该锁定指令包括非Thumb指令,但默认情况下IOS使用Thumb指令集。升压code,了解指令集的问题,检查,看看你有手臂启用但未拇指,但默认情况下,IOS,拇指是。

However, we're not done yet. The code used in boost for this option includes, as discussed, ARM assembly language instructions. The ARM chips support two instruction sets which can't be mixed in a given module (not sure of the scope, but evidently file by file is an acceptable granularity when compiling). The instructions used in boost for this locking include non-Thumb instructions, but IOS by default uses the Thumb instruction set. The boost code, aware of the instruction set issue, checks to see that you have arm enabled but not thumb, but by default in IOS, thumb is on.

获取编译器生成非拇指ARM $ C $,c取决于您使用的是IOS其中编译器 - 苹果的LLVM LLVM还是GCC。 GCC是德precated,和苹果的LLVM是默认的,当你使用的是X code。

Getting the compiler to generate non-thumb ARM code depends on which compiler you are using in IOS - Apple's LLVM or LLVM GCC. GCC is deprecated, and Apple's LLVM is the default when you use XCode.

有关默认锵+苹果LLVM 4.1,则需要使用-mno-大拇指标志进行编译。另外,在你的IOS应用程序,它使用它使用智能指针提振任何部分的文件也必须使用-mno拇指进行编译。

For the default Clang + Apple LLVM 4.1, you need to compile using the -mno-thumb flag. Also any files in your IOS app which use any part of boost which uses smart pointers will also have to be compiled using -mno-thumb.

要编译提升这个样子,我觉得你可以再补充-mno拇指在脚本的EXTRA_CPP_FLAGS。 (我修改直接而试验和尚未回到了清理用户config.jam中。)

To compile boost like this, I think you can just add -mno-thumb to the EXTRA_CPP_FLAGS in the script. (I modified the user-config.jam directly while experimenting and haven't yet gone back to clean up.)

有关您的应用程序,在X code您需要选择你的目标,然后进入构建阶段选项卡,并有选择编译来源。有你有添加编译标志的选项,因此每个相关文件(包括提升),加上-mno-大拇指标志。您可以直接在project.pbxproj做到这一点也是每个文件都有

For your app, in Xcode you need to select your target, then go into the Build Phases tab, and there select Compile sources. There you have the option of adding compile flags, so for each relevant file (which includes boost), add the -mno-thumb flag. You can do this directly in project.pbxproj also where each file has

settings = { COMPILER_FLAGS = ""; };   

您只需将其更改为

settings = { COMPILER_FLAGS = "-mno-thumb"; }; 

但还有更多一点。您还可以修改工具/编译/ V2 / tools目录中darwin.jam文件。在升压1.48,有一个code,上面写着:

But there's a little more. You also have to modify the darwin.jam file in the tools/build/v2/tools directory. In boost 1.48, there is a code that says:

    case arm :
    {
        options = -arch armv6;
    }

此已进行修改,以

    case arm :
    {
        options = -arch armv7 ;
    }        

最后,在boost.sh脚本,在功能 writeBjamUserConfig(),您应该删除引用-ARCH的ARMv6。

Finally, in the boost.sh script, in the function writeBjamUserConfig(), you should remove the references to -arch armv6.

如果有人知道如何将这个多一点一般,干净呢,我敢肯定,我们都会受益。现在,这是我已经得到了,我希望这将有助于其他iOS提升线程的用户。我希望在boost.sh IOS脚本的各种变种在那里将被更新。我打算多一些后来的链接添加到这个答案。

If somebody knows how to do this a little more generally and cleanly, I'm sure we'd all benefit. For now, this is where I've gotten to, and I hope that this will help other IOS boost threads users. I hope that the various variants on the boost.sh IOS script out there will be updated. I plan to add some more links to this answer later.

更新::用于描述对处理器的水平,结果这一问题的大文章
看这里:
的http:// preshing.com / 20121019 /这 - 是 - 为什么 - 他们叩它-A-弱有序CPU

Update: For a great article which describes the issue on the processor level,
see here: http://preshing.com/20121019/this-is-why-they-call-it-a-weakly-ordered-cpu

享受!

这篇关于升压线程:在IOS,的thread_info对象被线程完成执行前销毁的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆