开发者

CoreText crashes when run in multiple threads

I have a very weird problem with core text, which sometimes randomly and sometimes reproducibly crashes my application. I use it to lay out and render a couple of pages. I do this asynchronously in the background to not block the user interface.

While this works fine in general, it sometimes crashes. All these crashes happen on the very same line:

framesetter = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)myText);

In fact, they also also seem to come from a similar point in the framework. I know you don't like it, but here's the head of a crash log:

Thread 8 Crashed:
0   ???                             0x0764f446 typeinfo for FT::data_stream + 6
1   libCGFreetype.A.dylib           0x076048b8 FT::font::copy_table(unsigned int) const + 94
2   libCGFreetype.A.dylib           0x0760b085 (anonymous namespace)::copy_table(void*, unsigned int) + 53
3   CoreText                        0x00f9592e TBaseFont::CopyTable(unsigned int) const + 334
4   CoreText                        0x00f670f6 TAATMorphTable::TAATMorphTable(TLine&, long, unsigned int) + 110
5   CoreText                        0x00f6744c TAATMorphTableMorx::TAATMorphTableMorx(TLine&, long, TGlyphList<TDeletedGlyphIndex>&) + 54
6   CoreText                        0x00f53eb5 TShapingEngine::ShapeGlyphs(TLine&, TCharStream const&, CFRange&, TGlyphList<TDeletedGlyphIndex>*) + 215
7   CoreText                        0x00f579ce TTypesetter::FinishEncoding(TLine&, signed char, TGlyphList<TDeletedGlyphIndex>*) const + 260
8   CoreText                        0x00f6664b TTypesetterAttrString::Initialize(__CFAttributedString cons开发者_Go百科t*) + 543
9   CoreText                        0x00f6683e TTypesetterAttrString::TTypesetterAttrString(__CFAttributedString const*) + 158
10  CoreText                        0x00f6102e TFramesetterAttrString::TFramesetterAttrString(__CFAttributedString const*) + 86
11  CoreText                        0x00f6099e CTFramesetterCreateWithAttributedString + 78
...

All crashes I can remember have been in the FT::font::copy_table function. Interestingly, the more complicated the font-requirements, the more frequent the crashes. Chinese text nearly always crash -- those fonts seem to be quite complicated.

Workaround: The workaround I found is to sequentialize the calls to CTFramesetterCreateWithAttributedString in either the main queue or a separate one. The problem is that this single call makes up 79% of the total layout and rendering running time. So I would love to have it in multiple threads.

Question: Any Pros around that could help? To me this sounds like a race condition somewhere deep down. I didn't find anything stating that CoreText may not be used threaded. And I will file a bug tomorrow. However, I might also just have missed something. Any advice?

Thanks, Max


I've asked some of the engineers during WWDC whether they know the issue. The answer: YES. And there are in fact some problems in the type subsystem. They might be doing a fix some day, but for now all that is left to do is to sequentialize all text layout. :(

Everyone: PLEASE FILE BUGS!


Here is what the documentation says:

Multicore Considerations: All individual functions in Core Text are thread safe. Font objects (CTFont, CTFontDescriptor, and associated objects) can be used by simultaneously by multiple operations, work queues, or threads. However, the layout objects (CTTypesetter, CTFramesetter, CTRun, CTLine, CTFrame, and associated objects) should be used in a single operation, work queue, or thread.

So I guess there is no way around serialising calls to CTFramesetterCreateWithAttributedString.


CoreText takes a while to initialize the font lookup table when you use it for the first time. I imagine you might be able to get rid of your problem by first triggering a loading of this table before going to multiple threads.

See http://www.cocoanetics.com/2011/04/coretext-loading-performance/ for a method how.


Please make sure you're retaining the framesetter before reopening it. This is REALLY not meant to be used asynchronous before 4.0!

CFRelease(framesetter);

Could you also provide the Version of Xcode & iOS you're working with?


fix from me :-) no crash anymore

old code

NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:aText];
[attributedString addAttribute:(id)kCTFontAttributeName value:(id)aFontRef range:NSMakeRange(0, [aText length])];

CTFramesetterRef framesetterRef = CTFramesetterCreateWithAttributedString((CFAttributedStringRef)attributedString);

new code

CFMutableAttributedStringRef attributedStringRef = CFAttributedStringCreateMutable(nil, 0);
CFAttributedStringBeginEditing(attributedStringRef);
CFAttributedStringReplaceString(attributedStringRef, CFRangeMake(0, 0), (CFStringRef)aText);
CFAttributedStringSetAttribute(attributedStringRef, CFRangeMake(0, aText.length), kCTFontAttributeName, aFontRef);
CFAttributedStringEndEditing(attributedStringRef);

CTFramesetterRef framesetterRef = CTFramesetterCreateWithAttributedString(attributedStringRef); 
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜