NSThread detachNewThreadSelector 在主线程上执行
Posted
技术标签:
【中文标题】NSThread detachNewThreadSelector 在主线程上执行【英文标题】:NSThread detachNewThreadSelector executing on main thread 【发布时间】:2014-11-13 03:56:57 【问题描述】:一小部分客户从我的 OS X 应用程序中挂起,并带有以下挂起日志签名:
26 ??? [0x7fff93e87fc9]
26 ??? [0x7fff93e8372a]
26 ??? [0x7fff93e83899]
26 __NSThread__main__ + 1318 (Foundation) [0x7fff8be96dfb]
26 -[AppController startClean] + 1319 (Housekeeper) [0x100007742]
13 -[AppController trashMediaCache:] + 435 (Housekeeper) [0x100010e7a]
13 +[MYFileManager trashFilesOfType:inFolder:] + 482 (Housekeeper) [0x100022e2a]
13 +[MYFileManager trashFile:] + 22 (Housekeeper) [0x1000227f7]
12 +[MYFileManager trashFile:shouldAuth:] + 226 (Housekeeper) [0x1000228de]
12 -[NSWorkspace performFileOperation:source:destination:files:tag:] + 319 (AppKit) [0x7fff8aa72bbb]
12 -[NSWorkspace _fileOperation:source:destination:files:] + 917 (AppKit) [0x7fff8aa72f7e]
12 _FSOperateOnObjectSync + 482 (CarbonCore) [0x7fff87ab309c]
12 _NodeOperation + 488 (DesktopServicesPriv) [0x7fff90d6e38a]
4 TFSCopyOperation::DoMoveToTrash(TCountedPtr<TCFURLInfo> const&) + 330 (DesktopServicesPriv) [0x7fff90d7e28c]
4 TFSInfo::MoveAndRenameTo(TCountedPtr<TFSInfo> const&, TUString*, TCountedPtr<TFSInfo>&) const + 677 (DesktopServicesPriv) [0x7fff90da4ae7]
4 TCFURLInfo::RenameWithoutReplacing(char const*, char const*, bool) + 162 (DesktopServicesPriv) [0x7fff90d89620]
4 __rename + 10 (libsystem_kernel.dylib) [0x7fff861ba97a]
3 <Suppressed>
3 TFSCopyOperation::DoMoveToTrash(TCountedPtr<TCFURLInfo> const&) + 1033 (DesktopServicesPriv) [0x7fff90d7e54b]
3 THFSPlusPropertyStore::SetProperty(TUString const&, unsigned int, TPropertyReference const&) + 81 (DesktopServicesPriv) [0x7fff90d26bc1]
3 TDSMutex::Acquire() + 34 (DesktopServicesPriv) [0x7fff90ce5d00]
3 __psynch_mutexwait + 10 (libsystem_kernel.dylib) [0x7fff861ba746]
1 <Suppressed>
2 TFSCopyOperation::DoMoveToTrash(TCountedPtr<TCFURLInfo> const&) + 995 (DesktopServicesPriv) [0x7fff90d7e525]
2 THFSPlusPropertyStore::SetProperty(TUString const&, unsigned int, TPropertyReference const&) + 81 (DesktopServicesPriv) [0x7fff90d26bc1]
2 TDSMutex::Acquire() + 34 (DesktopServicesPriv) [0x7fff90ce5d00]
2 __psynch_mutexwait + 10 (libsystem_kernel.dylib) [0x7fff861ba746]
1 <Suppressed>
从日志中可以看出,startClean 正在主线程上运行。但令人困惑的是,只有一次调用 startClean,如下:
[NSThread detachNewThreadSelector:@selector(startClean) toTarget:self withObject:nil];
因此,代码应该在单独的线程上执行,实际上,这就是它在我的系统上的工作方式,但不止一位客户在 OS X 10.9.5 上遇到过这种情况。在 startClean 中有几个对主线程的调用,但这些仅用于更新 UI。垃圾媒体缓存调用由 performSelector:withObject: 执行,但不是 performSelectorOnMainThread。
有人见过这个吗?这是 OS X 的错误,还是存在系统设计将调用转移到主线程的情况?还是我只是误解了日志?
附:我知道我可以使用调度调用或操作队列,这可能会解决问题,但我仍然想知道原始问题的答案。
【问题讨论】:
【参考方案1】:显然,您在后台运行的startClean
方法会触发一些代码在主线程上运行,从而导致死锁。
一种可能性是startClean
使用核心数据。这被描述为here。
另一种可能性是在主线程上执行的完成处理程序。有很多,例如MKLocalSearchCompletionHandler
,文档明确声明它们始终在主线程上执行。
【讨论】:
我已经通过了我自己的代码,并且我确信没有任何东西进入主线程,所以它似乎很可能发生在 Apple 的代码中。我可能永远也不会追根究底。【参考方案2】:__NSThread__main__
不是主线程。它是 NSThread 执行的内部入口点。
【讨论】:
啊,我认为你是对的。我刚刚收到来自另一个应用程序的挂起报告,调用堆栈以main
而不是 __NSThread__main__
开头。以上是关于NSThread detachNewThreadSelector 在主线程上执行的主要内容,如果未能解决你的问题,请参考以下文章