2012-01-22 4 views
1

Я пытаюсь настроить сервер, который предоставляет истинно-случайный номер с устройства, Quantis - Quantum Random Number Generator. Я создал веб-приложение с платформой Grails, работая на сервере Tomcat по адресу Ubuntu.Очередь потоков одиночных ресурсов для потоков Grails/java

Поскольку есть только 1 устройство, я должен запланировать потоки, которые обращаются к нему, правильно? Поэтому я устанавливаю семафоры (с 1 ресурсом) на функции (ReadInt, ReadDouble, ReadFloat), которые вызывают это устройство. Объект, который содержит эти функции, называется Quantis, хранящимся в Java Source Packages для приложения 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. Это гарантирует, что она будет выпущена, то, что происходит внутри блока попробовать:

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

Четвертое: я не понимаю точку цикла while(true). Единственный раз, когда он зацикливается, возникает прерывание. И 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

Hi Nizet, Большое спасибо за ввод. Говоря о сбое, я имею в виду, когда есть несколько запросов на подключение к устройству, сервер 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. Это C-библиотека с оболочкой java. и из того, что я вижу, я не думаю, что он синхронизирован. Кроме того, прежде чем я сфотографировал семафор, он сразу же сработает, если я обновляю запрос очень быстро всего три раза. Поскольку исключений нет, и в сообщении об ошибке говорится (в самом конце), что ошибка возникает из-за пределов JVM, я уверен, что она исходит из библиотеки C, потому что несколько запросов запрашивают устройство, когда оно заблокировано используя текущую нить. –

+0

Я не эксперт в собственном коде, но, возможно, в библиотеке tye C, даже если только один поток вызывает его сразу, не может использоваться вообще несколькими потоками. В этом случае вы должны выделить один поток для использования API. Если это так (но это должно быть документировано!), И вы не знаете, как это сделать, задайте другой вопрос, и я буду рад ответить. –

Смежные вопросы