2012-01-22 2 views
1

장치에서 true-random number를 제공하는 서버를 설정하려고합니다. Quantis - Quantum Random Number Generator. 에 Tomcat 서버에서 실행되는 Grails 프레임 워크로 웹 응용 프로그램을 만들었습니다.Grails/java 단일 리소스 풀링 쓰레드 큐

장치가 하나뿐이므로 액세스하는 스레드를 예약해야합니다. 맞습니까? 그래서이 장치를 호출하는 함수 (ReadInt, ReadDouble, ReadFloat)에 세마포어 (1 리소스 사용)를 설정했습니다. 이 함수들을 포함하고있는 객체는이라고 불리며, Grails 애플리케이션을위한 자바 소스 패키지에 저장되어있다. 이것은 싱글 톤으로 구현되어있다; 컨트롤러는이 객체와 함수의 인스턴스를 호출하고 인스턴스를 생성합니다. 그런 다음 각 함수는 시스템의 Quantis 라이브러리를 호출하여 장치에서 스트림을 읽습니다. < - 이제 이것이 중요한 영역입니다. 이 기기에 한 번만 요청할 수 있도록해야합니다.

세마포어는 정상적으로 작동하는 것 같습니다. 그러나 페이지를 새로 고치면 (+/- 10 번과 같이) 빠른 속도로 임의의 숫자 스트림을 새로 고치면 충돌이 발생합니다. 나는 "맹목적으로"grails 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은 스레드가 가능한 빨리 실행을 중단해야 함을 알리는 데 정확하게 사용됩니다. 따라서 메서드는 삼키는 대신이 예외를 throw해야합니다.

마지막으로 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는 자바 API가 아닙니다. 자바 래퍼가있는 C 라이브러리입니다. 그리고 내가 본 것에서는 동기가 없다고 생각합니다. 또한 세마포어 전혀 구현하기 전에 즉시 충돌, 요청을 정말 빨리 세 번만 새로 고칩니다. 아무 예외도 없기 때문에 오류 메시지는 JVM 외부에서 오류가 발생한다고 말합니다. C 라이브러리에서 오는 것이 확실합니다. 여러 장치가 장치를 잠그고있는 동안 장치를 요청하기 때문입니다. 현재 쓰레드를 사용하고있다. –

+0

저는 원시 코드의 전문가는 아니지만 한 번에 하나의 스레드 만 호출해도 여러 스레드에서 전혀 사용할 수 없습니다. 이 경우 하나의 스레드를 API 사용 전용으로 사용해야합니다. 그렇다면 (문서화해야합니다!), 어떻게 해야할지 모르겠다. 또 다른 질문을하면, 나는 기꺼이 대답 할 것이다. –