我正在GCD提供的后台线程中检索NSRunningApplication
bundleIdentifier
,我使用的代码基本上是这样的:
NSWorkspace * __block workspace = [NSWorkspace sharedWorkspace];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND,
(unsigned long)NULL), ^(void) {
NSString *dateString = nil;
dateString = [dateFormat stringFromDate:[NSDate date]];
// here's where my app is getting locked
[foo doTheDinosaurWithAppName:[[workspace frontmostApplication] bundleIdentifier];
});
我面临的问题是,随机时间此调用将阻塞任务并且不会让它完成,这将在各种线程中发生,直到我达到我有超过64个锁定线程和我的点申请被终止,因为我已超出限制。
在查看流程时'使用Activity Monitor的信息,我得到了以下跟踪重复约67次(在许多其他事情中):
2317 Thread_5990845 DispatchQueue_4: com.apple.root.low-priority (concurrent)
+ 2317 start_wqthread (in libsystem_pthread.dylib) + 13 [0x7fff8e9d0fb9]
+ 2317 _pthread_wqthread (in libsystem_pthread.dylib) + 314 [0x7fff8e9cdef8]
+ 2317 _dispatch_worker_thread2 (in libdispatch.dylib) + 40 [0x7fff90678177]
+ 2317 _dispatch_root_queue_drain (in libdispatch.dylib) + 326 [0x7fff90677082]
+ 2317 _dispatch_client_callout (in libdispatch.dylib) + 8 [0x7fff9067528d]
+ 2317 _dispatch_call_block_and_release (in libdispatch.dylib) + 12 [0x7fff906781bb]
+ 2317 __45-[AppDelegate applicationDidFinishLaunching:]_block_invoke_2 (in XXXXXXXXX) + 251 [0x10bc7075b] AppDelegate.m:180
+ 2317 -[NSRunningApplication bundleIdentifier] (in AppKit) + 96 [0x7fff937d8468]
+ 2317 -[NSLock lock] (in Foundation) + 145 [0x7fff962428bb]
+ 2317 _pthread_mutex_lock (in libsystem_pthread.dylib) + 372 [0x7fff8e9cf779]
+ 2317 __psynch_mutexwait (in libsystem_kernel.dylib) + 10 [0x7fff8efc2746]
如果你看第9行,你可以看到我在说什么。
遵循Ken的建议,有一些痕迹(可能是6个)看起来有点不同,但它们似乎都指向同一条线:
2317 Thread_5993821 DispatchQueue_4: com.apple.root.low-priority (concurrent)
+ 2317 start_wqthread (in libsystem_pthread.dylib) + 13 [0x7fff8e9d0fb9]
+ 2317 _pthread_wqthread (in libsystem_pthread.dylib) + 314 [0x7fff8e9cdef8]
+ 2317 _dispatch_worker_thread2 (in libdispatch.dylib) + 40 [0x7fff90678177]
+ 2317 _dispatch_root_queue_drain (in libdispatch.dylib) + 326 [0x7fff90677082]
+ 2317 _dispatch_client_callout (in libdispatch.dylib) + 8 [0x7fff9067528d]
+ 2317 _dispatch_call_block_and_release (in libdispatch.dylib) + 12 [0x7fff906781bb]
+ 2317 __45-[AppDelegate applicationDidFinishLaunching:]_block_invoke_2 (in Keystats) + 251 [0x10bc7075b] AppDelegate.m:180
+ 2317 -[NSRunningApplication bundleIdentifier] (in AppKit) + 164 [0x7fff937d84ac]
+ 2317 -[NSRunningApplication _fetchStaticInformationWithAtLeastKey:] (in AppKit) + 94 [0x7fff93565a97]
+ 2317 _LSCopyApplicationInformation (in LaunchServices) + 2214 [0x7fff8f165adf]
+ 2317 LSClientToServerConnection::LSClientToServerConnection(int, __CFDictionary const*, bool) (in LaunchServices) + 255 [0x7fff8f161543]
+ 2317 LSClientToServerConnection::setupServerConnection(int, __CFDictionary const*) (in LaunchServices) + 160 [0x7fff8f1616f4]
+ 2317 xpc_connection_send_message_with_reply_sync (in libxpc.dylib) + 195 [0x7fff9a75f7ef]
+ 2317 _dispatch_semaphore_wait_slow (in libdispatch.dylib) + 206 [0x7fff906799f9]
+ 2317 semaphore_wait_trap (in libsystem_kernel.dylib) + 10 [0x7fff8efbea56]
我不知道这是NSRunningApplication
bundleIdentifier
中的错误,还是我错过了使用dispatch_async
的内容。
我在OSX 10.9.5中运行此代码。
答案 0 :(得分:1)
NSWorkspace对特定的方法是线程安全的。 -frontmostApplication
不是其中之一。转到NSWorkspace Class Reference 并查看每种方法的讨论。
请注意+sharedWorkspace
,-openFile:
,-openURL:
等明确说明:“在OS X v10.6及更高版本中,您可以从应用中的任何线程调用此方法。 “
-frontmostApplication
和其他人缺乏线程安全通知。它们目前是不安全的。
仅仅因为API是线程不安全的并不意味着当你在后台线程上调用它时它会100%挂起。它的行为与您所看到的完全一样:它大部分时间都会起作用,偶尔会出现死锁。
您只需要在主线程上调用frontmostApplication。
dispatch_async(dispatch_get_global_queue(0, 0), ^{
__block NSString *bundleIdentifier;
dispatch_sync(dispatch_get_main_queue(), ^{
bundleIdentifier = [[[NSWorkspace sharedWorkspace] frontmostApplication] bundleIdentifier];
});
[foo doTheDinosaurWithAppName:bundleIdentifier];
});
注意:这解决了NSWorkspace问题,但您可能在 -doTheDinosaurWithAppName:
中遇到其他线程问题。
编辑:实际上,Ken是对的(见下面的评论)。
虽然我上面说的一切都是正确的,但我的示例代码也很快地重现了这个问题。 --[NSRunningApplication bundleIdentifier]
正在向启动服务守护程序发出同步IPC调用,如果我在每次运行循环迭代时开始查询bundleID,我就能够轻松地使该连接饱和。
如果我每秒只查询100次bundleID,一切正常。