好的,我在阅读这篇文章及其在 Apple 邮件列表上的答案后想通了:http: //lists.apple.com/archives/quartz-dev/2006/Oct/msg00056.html
使用CC_MAC_USE_MAIN_THREAD
时,显示链接线程用于在主线程上performSelector:onThread:waitUntilDone:
运行。drawScene:
它传递参数YES
,waitUntilDone:
因此显示链接线程阻塞,直到主线程可以处理drawScene:
调用。
这是 cocos2d 代码的相关片段。MyDisplayLinkCallback
在显示链接线程上调用。
static CVReturn MyDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeStamp* now, const CVTimeStamp* outputTime, CVOptionFlags flagsIn, CVOptionFlags* flagsOut, void* displayLinkContext)
{
CVReturn result = [(CCDirectorDisplayLink*)displayLinkContext getFrameForTime:outputTime];
return result;
}
- (CVReturn) getFrameForTime:(const CVTimeStamp*)outputTime
{
#if (CC_DIRECTOR_MAC_THREAD == CC_MAC_USE_DISPLAY_LINK_THREAD)
...
#else
// Display link thread blocks here:
[self performSelector:@selector(drawScene) onThread:_runningThread withObject:nil waitUntilDone:YES];
#endif
return kCVReturnSuccess;
}
当主线程尝试运行CVDisplayLinkStop()
哪些阻塞直到显示链接线程中的显示链接回调完成时,就会出现问题。由于回调同时等待主线程处理它的 drawScene: 调用,所以两个线程都变成了deadlocked。
- (void) stopAnimation
{
...
if( displayLink ) {
// Main thread blocks here:
CVDisplayLinkStop(displayLink);
...
}
所以,现在我的解决方法。我添加了一行来运行主线程的 runloop,以强制执行drawScene:
调用,从而解除对显示链接线程的阻塞。这样,当你打电话时,CVDisplayLinkStop()
你是安全的。这是我的补充(cocos2d 2.1 版本中的 CCDirectorMac.m 第 473 行):
- (void) stopAnimation
{
...
if( displayLink ) {
#if (CC_DIRECTOR_MAC_THREAD != CC_MAC_USE_DISPLAY_LINK_THREAD)
[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
#endif
CVDisplayLinkStop(displayLink);
...
}
我不确定这是正确的做法,可能有更好的方法来处理这个问题,但这个解决方法目前对我来说已经足够好了。