0

编辑: 今天我使用了我的代码,并为后台线程任务提供了一些优于主线程任务的优势。本质上,一个线程处理数组中的偶数项,另一个线程处理奇数项。我给后台线程一个偶数的一半,它要么等于奇数的一半,要么比奇数的一半小一。此外,我将while(!collisionDone)代码移到了后面一点,尽可能地保证它的线程安全。我NSLog在其中放置了一个以检测条件在达到该点时是否为假,并且它没有触发一次。此外,仪器构建现在运行良好。这意味着问题是用 while 循环停止主线程。所以这意味着我现在的问题是:

我应该如何停止主线程以等待后台线程完成任务?也许演示如何使用NSLock来实现该功能?

今天我添加了多线程以试图减少我的游戏延迟。我正在使用 NSTimer 来调用我的时间循环函数,如下所示:

[NSTimer scheduledTimerWithTimeInterval:0.03 target:self selector:@selector(time:) userInfo: nil repeats: true];

然后,在那个函数中,我有:

//run collision using multithreading
    collisionDone = false;
    [self performSelectorInBackground:@selector(collideBackground:) withObject:objectToSend];
    [self collideMain:objectToSend];
    while (!collisionDone) {
        //notdone
    }

这个想法是我在一个线程上运行一组碰撞检查,在另一个线程上运行另一组。空的while循环是为了保证后台线程在执行函数之前已经完成。在此位之后,代码继续更新视图。

这一切运行良好,通常情况下,但是当我去 Instruments 检查我的 FPS 时,我发现游戏冻结了,它似乎在时间循环的第一次运行中冻结了某处。该应用程序在多线程之前在 Instruments 中运行良好,基本上工作相同,除了简单地使用[self collideBackground:objectToSend]而不是将其发送到另一个线程。后台线程似乎没有完成或根本没有运行,所以 collisionDone 将始终为 false,因此应用程序将在无限循环中等待,直到我杀死它。

另外,我尝试用 替换该行[self collideBackground:arrayToSend];,它又开始工作了。我尝试的另一件事是NSLog(@"called");在最开始时viewWillAppear:,它似乎又运行了一帧!?!?!?

我想知道为什么会发生这种情况以及如何解决它。我怀疑它与多线程无关,因为在单个线程上做所有事情都会修复它。

4

3 回答 3

0

是的,它与多线程有关,以及您在主线程上的投票。您应该改为将回调放入后台线程。并且不阻塞主线程。

// is not good at all
collisionDone = false;
/*  etc... that will make collision to true */
 while (!collisionDone) {
    }

改为制作

  [self computeSomethingOnBagroundWhithData: nil onCompletion:^{
    // callBack stuff
}]

编辑:

而 (!collisionDone)

总是正确的,因为当您创建另一个线程时,指令卡在“while”语句中,并且不会像您期望的那样每次“collisionDone”重新评估,而是在 while 范围内评估它。顺便说一句,可能有一些优化器的东西,“collisionDone”只能在本地范围内评估(但这里我只是猜测,因为它依赖于编译器)。您应该重新输入该方法以使其工作,或在完成后加入该线程。由于您不想要这种东西的复杂代码,因此 block 正是您想要的。libDispatch 非常适合这个。

所以你可以尝试“self.collisionDone”来尝试获取真正的指针。但有很多机会不会改变任何事情。

或者你可以在后台做你的事情,当你完成后,向你的客户端代码发送一个信号/回调。您不需要像以前那样进行投票。这真是糟糕的设计(真的相信我;))

于 2013-03-18T10:11:46.257 回答
0

目前还不清楚解决此问题的最佳方法或问题的实际原因是什么(是的while(!collisionDone)循环,但为什么?),但没有一个建议的替代方案可以正常工作。尽管已经提出了其他选项,但 NSThread 和 performSelectorInBackground: 是我检测到我正在寻找的功能的唯一方法。此外,在关闭多线程部分的测试后,我意识到 iPhone 4s 的处理器比 iPhone 4 好得多,而且我可以在 iPhone 4s 和更新版本(iPhone 4只能处理 30 FPS)。最后,我打算让我的多线程处理利用 iPhone 4s 的双核处理器,因此一半的冲突将在一个核心中完成,而另一个核心则在另一半中完成。我不确定这是否真的发生,我不知道如何检测到这一点。

我的结论:完全从应用程序中删除这种多线程尝试。这是不必要的,好处是可疑的。

@Fonix:您链接到的问题正是我正在尝试做的事情,但是,他们提出的解决方案似乎都没有奏效。

于 2013-03-20T00:24:28.493 回答
0

在学校和我的程序员朋友讨论后的最终解决方案:

//threadLock is an NSLock declared in the .h
-(void)timeLoop {
     [self performSelectorInBackground:@selector(collideBackground) withObject:nil];
     [self collideMainAtStartingPoint:0];

     [threadLock lock];
     [threadLock unlock];

     //update the view hierarchy and stuff like that
}
-(void)collideBack {
     [threadLock lock];
     [self collideMainAtStartingPoint:2];
     [threadLock unlock];
}
于 2013-03-23T02:21:59.010 回答