2016-10-06 1 views
1

私は小さなゲーム(Java、LibGdx)を開発しています。そこでは、プレイヤーがクローズスタイルの関数を定義済みのコード行で塗りつぶします。ゲームはコードをコンパイルし、小さなテストスイートを実行して、関数が想定されているものを実行していることを確認します。Java:潜在的にブロッキングコードを実行する

コードのコンパイルと実行は既に機能していますが、無限ループを検出する問題に直面しています。次の関数を考えてみましょう:

// should compute the sum of [1 .. n] 
public int foo(int n) { 
    int i = 0; 
    while (n > 0) { 
     i += n; 
     // this is the place where the player inserts one of many predefined lines of code 
     // the right one would be: n--; 
     // but the player could also insert something silly like: i++; 
    } 
    return i; 
} 

実際に使用される関数が複雑化することができ、一般に、すべての無限ループがないことを確認することはできませんのでご注意ください。

現在、私はExecutorServiceを使用してスレッド内の小さなテストスイートを実行しています(スレッドごとに用意されています)。これの問題は、無限ループに詰まったスレッドがバックグラウンドで永遠に実行されることです。もちろん、ある時点ではゲームのパフォーマンスに大きな影響を与えます。

// TestClass is the compiled class containing the function above and the corresponding test suite 
Callable<Boolean> task = new Callable<Boolean>() { 
    @Override 
    public Boolean call() throws Exception { 
     // call the test suite 
     return new TestClass().test(); 
    } 
}; 
Future<Boolean> future = executorService.submit(task); 
try { 
    Boolean result = future.get(100, TimeUnit.MILLISECONDS); 
    System.out.println("result: " + (result == null ? "null" : result.toString())); 
} catch (InterruptedException e) { 
    e.printStackTrace(); 
} catch (ExecutionException e) { 
    e.printStackTrace(); 
} catch (TimeoutException e) { 
    e.printStackTrace(); 
    future.cancel(true); 
} 

私の質問は以下のようになります。どのように私は優雅に誤って無限ループ内でスピンスレッドを終了することができますか?

* EDITこの場合、無限ループを防止することができない/実行可能でないことを明確にするために、関数、テストスイート、ギャップを埋める行がディスクから読み込まれます。コードの少なくとも2行が挿入された関数のhundretsがあります。プレーヤーはのいずれかの行を任意の間隔にドラッグできます。関数ギャップ/コードラインの組み合わせが無限にループするか、タイムアウトよりも長く実行されるものを生成しないことを確認するために必要な努力は、関数の数によって指数関数的に増加します。これはすぐに誰もがこれらの組み合わせをすべて手動でチェックする時間がないようになります。また、一般的に、関数が時間内に終了するかどうかを判断することは、停止問題のために不可能です。

答えて

1

同じプロセス内にスレッドの「正常終了」はありません。終了したスレッドは、その背後に一貫性のない共有メモリ状態を残す可能性があります。

各タスクが独自のJVMで起動されるように構成するか、非推奨のThread.stop()メソッドを使用して強制終了することができます。

もう一つのオプションは、生成されたコードにチェックを挿入することですが、これは適切に実装するためにより多くの労力が必要になります。

+0

ありがとうございました:)残念ながら、 'Thread.stop()'はもう動作しません。別のJVMでタスクを実行する方法に関する情報はありますか? (これもパフォーマンスを殺すのではないかと心配しています...) – LostMekkaSoft

+0

'Thread.stop()'は動作します。子JVMは 'Runtime.exec()'を使って起動します。小さな仕事がたくさんあると、パフォーマンスが低下します。 –

+0

Youre right、それは動作します。私がExecutorServiceに入力したスレッドを止めるだけで動作しないものは唯一のものです:)今は、タイムアウトを検出できる間にスレッドを制御できるセットアップが必要です。 ExecutorServiceは私にスレッドオブジェクトを与えません。どのようにそれを行う上の任意のアイデアですか? – LostMekkaSoft

1

正しい方法は、デザインを変更して、決してループを終了させないようにすることです。

当面のためにスレッドがでいくつかの方法が中断された場合は、あなたのループ内であなたがチェックすることができ:isInterruptedを()あるいはのisAlive()

もしあなたがただ終了していれば。

+0

これは、コードをコンパイルする前にこれらのチェックをすべてのループに挿入することを意味します。理論的にはこれは可能ですが、かなり醜いと思われます...テストスイートを呼び出すときのように、私が何らかの** **機能の外で何かを行うことができるのだろうかと思っていました... あなたは考えがありますか最初の無限ループを回避する方法について?それは確かに最もクリーンな解決策になるだろうが、私はこれがこの問題のために可能であることを確信していない...(私の質問編集を参照してください) – LostMekkaSoft

+0

スレッドは、外部から停止されているかどうかを確認する責任があります。これは、スレッドがブロッキングと非常に長いタスクを実行する場合、マルチスレッドでコード化する適切な方法です。私はあなたのポイントを得る、あなたは変更する膨大な量のコードを持っています。ここを見てくださいhttp://stackoverflow.com/questions/10961714/how-to-properly-stop-the-thread-in-javaより完全な答えですが、あなたが探しているものは確実ではありません。 –

0

不要なループが存在するのは通常ではありません。

問題を解決するにはループ内にカウンタを追加できます。制限に達すると終了することができます。

int counter = 0; 
while (n > 0) { 
    counter++; 
    if (counter > THRESHOLD) { 
     break; 
    } 
    i += n; 
    // this is the place where the player inserts one of many predefined lines of code 
    // the right one would be: n--; 
    // but the player could also insert something silly like: i++; 
}