2012-01-22 8 views
1

デバイスから真の乱数を提供するサーバを設定しようとしています。Quantis - Quantum Random Number Generator私はのTomcatサーバ上で動作するGrailsフレームワークを使ってWebアプリケーションを構築しました。Grails/Java単一リソースプーリングスレッドキュー

デバイスが1つしかないので、アクセスするスレッドをスケジュールする必要がありますが、正しいですか?そこで、このデバイスを呼び出す関数(ReadInt, ReadDouble, ReadFloat)にセマフォ(1リソース)を設定しました。これらの関数を含むオブジェクトは、GrailsアプリケーションのJavaソースパッケージに格納されているQuantisと呼ばれ、シングルトンとして実装されています。コントローラはこのオブジェクトとそれの関数を呼び出してインスタンス化します。これらの各機能は、システム上のQuantisライブラリを呼び出して、デバイスからストリームを読み込みます。< - これがクリティカルゾーンです。このデバイスに一度に1つのリクエストしかないことを確認する必要があります。

セマフォーは正常に動作しているようです。しかし、ページをリフレッシュして(乱数のストリームを取得して)本当に速く(+/- 10回など)クラッシュします。私は "盲目的に"グレイスexecutorsを含むインターネットからの多くのアプローチを試みたが、何も動作しないようだ(しかし、私は正しく、実際にそれらを実装していない可能性があります)。

私はこれをどのように解決することができますか?それはをクラッシュします」、すべての

 
    private static final Semaphore ticket = new Semaphore(1, true); 
    ... 
    public int ReadInt(int min, int max) throws QuantisException { 
     while (true) { 
      try { 
       ticket.acquire(); 
       int data = QuantisReadScaledInt(deviceType.getType(), deviceNumber, min, max); 
       ticket.release(); 
       return data; 
      } catch (InterruptedException ex) { 
      } catch (QuantisException ex) { 
       ticket.release(); 
       throw ex; 
      } 
     } 
    } 

答えて

1

まず、(データを取得するとき、それらはすべて同じスタイルについて見えるが、異なるシステムライブラリ関数を呼び出す):

は、ここでの関数のいずれかのために私のコードです"何が起こるかについての貧弱な記述です。例外はありますか?正確にはどうなりますか?

次に、APIへのアクセスを同期する必要がありますか? Java APIが提供されている場合、このAPIがすでに同期されている可能性があり、セマフォーは不要です。

セマフォを取得した場合は、finallyブロックで解放する必要があります。これは、tryブロックの内部で起こるものは何でも、それがリリースされることを保証:

ticket.acquire(); 
try { 
    ... 
} 
catch (...) 
finally { 
    ticket.release(); 
} 

第四:私はwhile(true)ループのポイントを理解していません。ループするのは、InterruptedExceptionが存在するときだけです。 InterruptedExceptionは、ASAPの実行を停止すべきであることをスレッドに通知するために使用されます。したがって、あなたのメソッドはそれを飲み込む代わりにこの例外をスローする必要があります。

最後に、Java命名規則を学び、それらに固執する必要があります。メソッドは小文字で始まります。

public int readInt(int min, int max) throws QuantisException, InterruptedException { 
    ticket.acquire(); 
    try { 
     return quantisReadScaledInt(deviceType.getType(), deviceNumber, min, max); 
    } 
    finally { 
     ticket.release(); 
    } 
} 

一つだけのスレッドがネイティブライブラリ関数にアクセスできることを確認したい場合は、そのようなクラスを使用する:あなたは本当にここで私はメソッドを書き換えるだろうかこれで、アクセスを同期する必要が提供

import java.util.concurrent.Callable; 
import java.util.concurrent.ExecutionException; 
import java.util.concurrent.ExecutorService; 
import java.util.concurrent.Executors; 
import java.util.concurrent.Future; 
import java.util.concurrent.TimeUnit; 

public class SingleThreadAccess { 
    public static final SingleThreadAccess INSTANCE = new SingleThreadAccess(); 

    private ExecutorService executor; 

    // to be called by ServletContextListener.contextInitialized() 
    public void init() { 
     executor = Executors.newSingleThreadExecutor(); 
    } 

    // to be called by ServletContextListener.contextDestroyed() 
    public void shutdown() { 
     executor.shutdown(); 
     try { 
      executor.awaitTermination(2L,TimeUnit.SECONDS); 
     } 
     catch (InterruptedException e) { 
     } 
     executor.shutdownNow(); 
    } 

    public int readInt(int min, int max) throws QuantisException, InterruptedException { 
     Callable<Integer> task = new Callable<Integer>() { 
      @Override 
      public Integer call() throws QuantisException { 
       return quantisReadScaledInt(deviceType.getType(), deviceNumber, min, max); 
      } 
     }; 
     Future<Integer> future = executor.submit(task); 
     try { 
      future.get(); 
     } 
     catch (ExecutionException e) { 
      unwrap(e); 
     } 
    } 

    private void unwrap(ExecutionException e) throws QuantisException { 
     Throwable t = e.getCause(); 
     if (t instanceof QuantisException) { 
      throw (QuantisException) t; 
     } 
     throw new RuntimeException(e); 
    } 
} 
+0

こんにちは、入力していただきありがとうございます。クラッシュを言うと、私はデバイスに要求する複数の接続があるとき、Tomcatサーバーがクラッシュし、ログ出力:

 libusb:warning [libusb_open] internal signalling write failed # # A fatal error has been detected by the Java Runtime Environment: # # SIGSEGV (0xb) at pc=0x00007f095e06e288, pid=9879, tid=139678215476992 # ... 
セマフォを実装すると、複数の接続送信でテストするまで実際にはうまく動作しますリクエストを本当に速く(リフレッシュする)ことができます。 ありがとう、私はあなたがちょうど言ったことをしようとします。 –

+0

ああ、ほとんど忘れていた:いいえ、APIはJava APIではありません。これは、Javaラッパーを持つCライブラリーです。私が見るものから、私はそれが同期しているとは思わない。また、私はまったくセマフォーを実装する前に、すぐにクラッシュします。もしリクエストを本当に速く3回だけリフレッシュすれば、例外はなく、エラーメッセージはJVMの外部からエラーが出ていると言いますが、Cライブラリから来ていると確信しています。現在のスレッドを使用します。 –

+0

私はネイティブコードの専門家ではありませんが、たぶん1つのスレッドだけを呼び出すときでさえ、複数のスレッドでは全く使用できません。この場合、1つのスレッドをAPIの使用専用にする必要があります。それが事実なら(それは文書化されるべきです!)、あなたはやり方を知らないので、別の質問をしてください。そして、私は幸せになるでしょう。 –