2012-10-05 2 views
2

Я вижу, что мое приложение застряло в состоянии тупикового (основной поток ожидает в semaphore_wait_trap см называют стеки ниже) несколько раз при вызове более одного экземпляра CFStringTransform одновременно в глобальной очереди фона следующим образом:Является ли CFStringTransform потоком безопасным и повторным?

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 
    CFStringTransform(…); 
}); 

стеки вызовов выглядят эти:

Thread 1, Queue : com.apple.main-thread 
#0 0x310bff04 in semaphore_wait_trap() 
#1 0x341c1fae in _dispatch_semaphore_wait_slow() 
#2 0x32bc5c32 in SBSProcessAssertionCreateForPID() 
#3 0x3685bca4 in -[UIApplication beginBackgroundTaskWithExpirationHandler:]() 
#4 0x0011a1c2 in -[XXX downloadPicture:] 
… 
#10 0x32f86a6e in __NSFireDelayedPerform() 
#11 0x354a15de in __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__() 
#12 0x354a1290 in __CFRunLoopDoTimer() 
#13 0x3549ff00 in __CFRunLoopRun() 
#14 0x35412ebc in CFRunLoopRunSpecific() 
#15 0x35412d48 in CFRunLoopRunInMode() 
#16 0x3594f2ea in GSEventRunModal() 
#17 0x367f1300 in UIApplicationMain() 
#18 0x000c3eb8 in main 


Thread 3, Queue : com.apple.libdispatch-manager 
#0 0x310c0648 in kevent64() 
#1 0x341c3978 in _dispatch_mgr_invoke() 
#2 0x341c3658 in _dispatch_mgr_thread$VARIANT$mp() 


Thread 5 WebThread, Queue : (null) 
#0 0x310bfeb4 in mach_msg_trap() 
#1 0x310c004c in mach_msg() 
#2 0x354a1044 in __CFRunLoopServiceMachPort() 
#3 0x3549fda2 in __CFRunLoopRun() 
#4 0x35412ebc in CFRunLoopRunSpecific() 
#5 0x35412d48 in CFRunLoopRunInMode() 
#6 0x349b6a74 in RunWebThread(void*)() 
#7 0x3925f310 in _pthread_start() 
#8 0x3925f1d8 in thread_start() 


Thread 11 com.apple.NSURLConnectionLoader, Queue : (null) 
#0 0x310bfeb4 in mach_msg_trap() 
#1 0x310c004c in mach_msg() 
#2 0x354a1044 in __CFRunLoopServiceMachPort() 
#3 0x3549fda2 in __CFRunLoopRun() 
#4 0x35412ebc in CFRunLoopRunSpecific() 
#5 0x35412d48 in CFRunLoopRunInMode() 
#6 0x32f0bbcc in +[NSURLConnection(Loader) _resourceLoadLoop:]() 
#7 0x32f8f67c in __NSThread__main__() 
#8 0x3925f310 in _pthread_start() 
#9 0x3925f1d8 in thread_start() 


Thread 14 com.apple.CFSocket.private, Queue : (null) 
#0 0x310d0594 in select$DARWIN_EXTSN() 
#1 0x354a51f6 in __CFSocketManager() 
#2 0x3925f310 in _pthread_start() 
#3 0x3925f1d8 in thread_start() 

и 31 нити вызова CFStringTransform:

Thread 12, Queue : com.apple.root.default-priority 
#0 0x310d00fc in __psynch_mutexwait() 
#1 0x3924f128 in pthread_mutex_lock() 
#2 0x31448548 in umtx_lock() 
#3 0x3144a090 in icu::UnicodeString::doReplace(int, int, unsigned short const*, int, int)() 
#4 0x314a5b3a in icu::UnicodeString::append(int)() 
#5 0x314a1510 in icu::UnicodeSet::_appendToPat(icu::UnicodeString&, int, signed char)() 
#6 0x314a168c in icu::UnicodeSet::_generatePattern(icu::UnicodeString&, signed char) const() 
#7 0x314a2e4e in icu::UnicodeSet::applyPattern(icu::RuleCharacterIterator&, icu::SymbolTable const*, icu::UnicodeString&, unsigned int, icu::UnicodeSet& (icu::UnicodeSet::*)(int), UErrorCode&)() 
#8 0x314a1e7c in icu::UnicodeSet::applyPattern(icu::UnicodeString const&, icu::ParsePosition&, unsigned int, icu::SymbolTable const*, UErrorCode&)() 
#9 0x314a1e06 in icu::UnicodeSet::UnicodeSet(icu::UnicodeString const&, icu::ParsePosition&, unsigned int, icu::SymbolTable const*, UErrorCode&)() 
#10 0x314a1d8e in icu::UnicodeSet::UnicodeSet(icu::UnicodeString const&, icu::ParsePosition&, unsigned int, icu::SymbolTable const*, UErrorCode&)() 
#11 0x314fe56c in ___lldb_unnamed_function2011$$libicucore.A.dylib() 
#12 0x314fda50 in ___lldb_unnamed_function2010$$libicucore.A.dylib() 
#13 0x314fd954 in ___lldb_unnamed_function2009$$libicucore.A.dylib() 
#14 0x314ff540 in ___lldb_unnamed_function2031$$libicucore.A.dylib() 
#15 0x314feed6 in ___lldb_unnamed_function2025$$libicucore.A.dylib() 
#16 0x314feb0c in ___lldb_unnamed_function2024$$libicucore.A.dylib() 
#17 0x31521468 in ___lldb_unnamed_function2248$$libicucore.A.dylib() 
#18 0x3152015a in icu::Transliterator::createBasicInstance(icu::UnicodeString const&, icu::UnicodeString const*)() 
#19 0x31522cd6 in ___lldb_unnamed_function2296$$libicucore.A.dylib() 
#20 0x31523c32 in ___lldb_unnamed_function2305$$libicucore.A.dylib() 
#21 0x3152003a in icu::Transliterator::createInstance(icu::UnicodeString const&, UTransDirection, UParseError&, UErrorCode&)() 
#22 0x315200d6 in icu::Transliterator::createInstance(icu::UnicodeString const&, UTransDirection, UErrorCode&)() 
#23 0x314bfc1c in ___lldb_unnamed_function1051$$libicucore.A.dylib() 
#24 0x314bfb0e in ___lldb_unnamed_function1050$$libicucore.A.dylib() 
#25 0x3151fada in icu::Transliterator::filteredTransliterate(icu::Replaceable&, UTransPosition&, signed char, signed char) const() 
#26 0x3151f724 in icu::Transliterator::transliterate(icu::Replaceable&, int, int) const() 
#27 0x3154a8da in utrans_trans() 
#28 0x354b3928 in CFStringTransform() 
#30 0x002716c8 in __18-[Foo bar]_block_invoke_0 
#31 0x341bd11e in _dispatch_call_block_and_release() 
#32 0x341c1960 in _dispatch_root_queue_drain() 
#33 0x341c1ac0 in _dispatch_worker_thread2() 
#34 0x39254a10 in _pthread_wqthread() 
#35 0x392548a4 in start_wqthread() 

Похоже, что проблема возникает при вызове модификации строки doReplace. Но также кажется, что doReplace является потокобезопасным, так как он использует мьютекс, поэтому для нескольких потоков должно быть хорошо, чтобы одновременно изменять одну и ту же изменяемую строку. Фактически, в моем случае ни одна изменяемая строка не изменяется более чем одним потоком - каждый из CFStringTransform вызывается для уникальной строки. Так что, в основном, я не знаю, почему он застрял.

ответ

0

Интересно.

Преобразование строк ICU находится в библиотеке под названием libicucore. Исходный код версии Mac OS 10.8 is available here.

Функция doReplace реализована в icuSources/common/unistr.cpp, но это не называется umtx_lock. iOS может использовать другую версию библиотеки или вызов может быть только внутри встроенной функции (или магии препроцессора). Таким образом, я не мог узнать, является ли блокировка глобально разделяемой блокировкой или если есть одна строка.

Во всяком случае, я провел некоторое тестирование на Mac OS (строки 24k символов, 10000 отправленных блоков), но не удалось воспроизвести тупик.

Вы уверены, что ваш код еще не работает? Все ли потоки в одном стеке стека?

+0

Да, он застрял, и все потоки, вызывающие 'doReplace', имеют одну и ту же трассировку стека. Как вы обнаружили, что iOS и OS X разные, может быть, вам следует протестировать iOS? – an0