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
    }

アイデアは、あるスレッドで1セットの衝突チェックを実行し、別のスレッドで別のセットを実行しているということです。空のwhileループは、関数を続行する前にバックグラウンドスレッドが完了したことを確認するためのものです。このビットの後、コードはビューを更新します。

これはすべて正常に実行されますが、FPSを確認するためにInstrumentsにアクセスしたところ、ゲームがフリーズしていることがわかりました。タイムループの最初の実行のどこかでフリーズしているようです。アプリはマルチスレッドの前にInstrumentsで正常に実行されました。マルチスレッドは、[self collideBackground:objectToSend]別のスレッドに送信するのではなく単に使用することを除いて、基本的に同じように機能しました。バックグラウンドスレッドが完了していないか、まったく実行されていないように見えるため、collisionDoneは常にfalseになります。したがって、アプリは、強制終了するまでその無限のループで待機します。

また、その行をに置き換えてみたところ、[self collideBackground:arrayToSend];再び動作し始めました。私が試したもう一つのことは、最初に置くことNSLog(@"called");です、viewWillAppear:そしてそれはちょうどもう1つのフレームを実行しているようです!?!?!?

なぜこれが起こっているのか、そしてそれをどのように修正するのかについてのアイデアが欲しいです。シングルスレッドですべてを実行すると修正されるため、マルチスレッドとは無関係ではないかと思います。

4

3 に答える 3

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 に答える
0

はい、マルチスレッドとメインスレッドでのポーリングに関連しています。代わりに、バックグラウンド スレッドにコールバックを配置する必要があります。メインスレッドをブロックしません。

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

代わりに作る

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

編集:

while (!collisionDone)

別のスレッドを作成しているとき、命令は「while」ステートメントでスタックされ、期待どおりに「collisionDone」のたびに再評価されるわけではなく、while スコープ内で評価されるため、常に true です。ちなみに、いくつかのオプティマイザーが存在する可能性があり、「collisionDone」はローカルスコープでのみ評価できます(ただし、コンパイラに依存するため、ここでは推測にすぎません)。メソッドを機能させるには、メソッドを再入力するか、完了したらスレッドに参加する必要があります。この種のものには複雑なコードが必要ないため、ブロックはまさに​​必要なものです。libDispatch はこれに最適です。

したがって、本物のポインターを取得するために「self.collisionDone」を試すことができます。しかし、何も変わらない可能性は十分にあります。

または、バックグラウンドで作業を行い、完了したら、シグナル/コールバックをクライアント コードに送信することもできます。あなたがしたようにポーリングを行う必要はありません。これは本当に悪い設計です (本当に私を信じてください ;))

于 2013-03-18T10:11:46.257 に答える
0

この問題を解決するための最善のアプローチや、問題の実際の原因は不明です (はい、それはwhile(!collisionDone)ループしますが、なぜですか?)、しかし、提案された代替案はどれも適切に仕事をすることができません。他のオプションが提案されていますが、NSThread と performSelectorInBackground: は、私が探している機能を検出する唯一の方法でした。さらに、マルチスレッド部分をオフにしてテストしたところ、iPhone 4s は iPhone 4 よりもはるかに優れたプロセッサを搭載しており、iPhone 4s 以降ではマルチスレッド (iPhone 4) なしで 60 FPS でゲームを実行できることがわかりました30 FPS しか処理できません)。最後に、マルチスレッドで iPhone 4s のデュアルコア プロセッサを利用することを意図していたので、衝突の半分は 1 つのコアで行われ、残りの半分は他のコアで行われます。これが実際に起こっているかどうかはわかりませんし、これを検出する方法もわかりません。

私の結論: このマルチスレッド化の試みをアプリから完全に削除してください。それは不要であり、その利点は疑わしいです。

@Fonix:リンク先の質問は、私がやろうとしていることを正確に示していますが、提示された解決策はどれも機能していないようです.

于 2013-03-20T00:24:28.493 に答える