Objective c NSRunningApplication bundleIdentifier锁定我的异步应用程序
我正在由GCD提供服务的后台线程中检索Objective c NSRunningApplication bundleIdentifier锁定我的异步应用程序,objective-c,macos,grand-central-dispatch,appkit,Objective C,Macos,Grand Central Dispatch,Appkit,我正在由GCD提供服务的后台线程中检索NSRunningApplication的bundleIdentifier,我使用的代码基本上如下所示: NSWorkspace * __block workspace = [NSWorkspace sharedWorkspace]; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND,
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次(除其他外):
如果你看第九行,你就会明白我在说什么
按照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
中的一个bug,或者我使用dispatch\u async
时是否遗漏了什么
我在OSX 10.9.5中运行这段代码。NSWorkspace对于特定方法是线程安全的<代码>-frontmostApplication不是其中之一。转到并查看每个方法的讨论 请注意,
+sharedWorkspace
,-openFile:
,-openURL:
,等等明确声明:“在OS X v10.6及更高版本中,从应用程序中的任何线程调用此方法都是安全的。”
-frontmostApplication
和其他应用程序缺少螺纹安全注意事项。它们目前是线程不安全的
仅仅因为API是线程不安全的,并不意味着当您在后台线程上调用它时,它将100%挂起。它将完全按照您所看到的那样运行:它将在大部分时间工作,偶尔会死锁
您只需在主线程上调用frontmostApplication
注意:这修复了NSWorkspace问题,但在-doTheDinosaurWithAppName:
中可能存在其他线程问题
编辑:事实上,肯是对的(见下面的评论)
虽然我上面所说的一切都是正确的,但我的示例代码也相当快地再现了这个问题<代码>-[NSRunningApplication bundleIdentifier]正在向启动服务守护程序发出同步IPC调用,如果我开始在每次运行循环迭代中查询bundleId,我很容易使该连接饱和
如果我每秒只查询bundleID 100次,一切都正常。您是否尝试过从主线程运行它,因为工作区不是线程安全的?其他线程在做什么?您是否让主线程运行事件循环?@Wain NSWorkspace在大多数情况下(在后台线程中)都可以正常工作。这种情况很少发生。@kenthomas所有其他线程都在做同样的事情,它们获取最前面的应用程序包id,然后以相同的方式处理它。我让主线程运行事件循环,我没有在主线程中运行任何东西(除了GUI更改)。它们是否都在完全相同的位置被阻止?想必,有什么东西成功地锁定了其他人试图锁定的那把锁,但随后继续并在其他地方卡住了。你想找到另一个,看看它卡在哪里。(有可能是某个bug导致锁定它的线程无法解锁,即使它没有被卡住。但我认为这是一个较低的概率。)也许。我通常也是一个固执的人,因为我只依赖于有文件证明的线程安全承诺。但是,
-runningApplications
记录为线程安全,而NSRunningApplication
的所有属性(包括活动的
)记录为线程安全。因此,以线程安全的方式实现-frontmostApplication
是相当简单的。此外,所观察到的挂起是在NSRunningApplication
代码内部,因此-frontmostApplication
显然起了作用,而NSRunningApplication
内部的某些东西被破坏了,尽管它应该是线程安全的。实际上,您是正确的。好电话。当我用我的代码做一个示例项目时,它显示了相同的问题。如果您开始在每个运行循环周期要求bundleID,则项目排队的速度将快于ls守护进程(bundleID最终阻止了它)的响应速度。感谢您的精彩讨论!不确定我是否应该将这个问题标记为已回答,因为这似乎可能是一个bug。有什么建议吗?老实说,我觉得这个问题还没有完全解决。您是否可以发布更多关于调用-bundleIdentifier
的块的频率的代码?如果您在每次运行循环迭代中都调用它,那么您肯定处于队列随时间累积的情况。
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]
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];
});