1

我们正在构建一个内容编辑器,它会在一个“cocos Player”中NSWindow进行测试。用户可以测试一些内容,然后关闭窗口。

所以我需要能够关闭 cocos 并在同一个应用程序中重新启动。

CC_MAC_USE_DISPLAY_LINK_THREAD如果我使用线程模型,一切正常。我必须进行修复才能使其CCDirectorMac正常工作。在CCDirectorMac | stopAnimation我必须设置为_runningThreadnil因为它没有被设置为零#if并且#elif使用时CC_MAC_USE_DISPLAY_LINK_THREAD

无论如何,现在我可以“结束”一个导演,然后再重新开始,没有任何问题。

不过我的问题是:如果我正在构建一个偶尔使用 cocos2D 的 AppKit 编辑器,我的线程模型真的会CC_MAC_USE_MAIN_THREAD按照文档中的建议吗?

当我使用时,我CC_MAC_USE_MAIN_THREAD挂断stopAnimation电话:

CVDisplayLinkStop(displayLink);

我认为主线程会很好,并且可以避免我们工具的线程问题。性能不是问题。我找不到任何关闭并重新启动 cocos2d 的示例代码NSWindow......所以我在这里的假设是我处于未经测试的水域(或很少经过测试的水域)。

我关闭/重启的步骤是:

  1. 称呼[[CCDirector sharedDirector] end]
  2. 这叫stopAnimation
  3. 然后按照我最初的方式重新初始化 cocos2d

任何关于 Mac 桌面应用程序线程模型的建议......以及为什么CVDisplayLinkStop挂起将不胜感激。

提前致谢。

4

2 回答 2

3

好的,我在阅读这篇文章及其在 Apple 邮件列表上的答案后想通了:http: //lists.apple.com/archives/quartz-dev/2006/Oct/msg00056.html

使用CC_MAC_USE_MAIN_THREAD时,显示链接线程用于在主线程上performSelector:onThread:waitUntilDone:运行。drawScene:它传递参数YESwaitUntilDone:因此显示链接线程阻塞,直到主线程可以处理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);
    ...
}

我不确定这是正确的做法,可能有更好的方法来处理这个问题,但这个解决方法目前对我来说已经足够好了。

于 2013-08-03T03:34:09.787 回答
0

感谢这篇文章,它帮助我弄清楚了如何在非 cocos2d 应用程序中解决相同的死锁,方法是在单独的线程上处理显示链接回调,而不是在主线程上。

static CVReturn MyDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeStamp* now, const CVTimeStamp* outputTime,
                                      CVOptionFlags flagsIn, CVOptionFlags* flagsOut, void *userInfo)
{
    static dispatch_queue_t sDisplayQueue;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sDisplayQueue = dispatch_queue_create("com.company.app.displayLink", NULL);
    });

    dispatch_sync(sDisplayQueue, ^{
        <stuff>
    });
    return kCVReturnSuccess;
}
于 2018-08-14T15:09:46.320 回答