2014-01-30 5 views
3

В настоящее время я создаю приложение в JAVA, где может быть только одно исполнение. Поэтому в настоящее время я использую файл блокировки, в котором я пишу PID текущего исполнения.Проверьте, выполняется ли процесс с использованием его PID в JAVA.

Итак, всякий раз, когда это приложение запустится, он откроет файл (если он существует) и попытается определить, действительно ли PID, записанный в файле, запущен.

Это предотвращает проблему, когда мое приложение падает до разблокировки файла.

Мне нужно, чтобы это работало как на окнах (XP, 7 или 8), так и на Linux (все пользователи находятся на дистрибутивах на основе debian).

Вот код, чтобы дать вам более полную картину того, что я хочу сделать:

//get the PID from the file 
int pidValue = new FileReader(file).read(); 

//get the OS type 
String os = System.getProperty("os.name").toLowerCase(); 

//Check PID depending of OS type 
if(os.contains("nux") || os.contains("nix")){ 
/* 
* Check PID on Linux/Unix 
*/ 
} else if (os.contains("win")) { 
/* 
* Check PID on Windows 
*/ 
} 

Я пытался найти документацию по этому вопросу, но мне не удалось найти ничего полезного пока.

спасибо.

+0

Вы можете выполнить процесс с 'ps' для linux и' tasklist' для окон и проверить вывод для PID. – PeterMmm

+0

Эти функции возвращают какой-то ответ? Мне нужно программно определить, работает ли процесс. – ElCapitaine

+0

http://stackoverflow.com/questions/54686/how-to-get-a-list-of-current-open-windows-process-with-java – PeterMmm

ответ

2

В системах posix типичный способ запроса, если pid работает, - отправить ему нулевой сигнал, например. kill(pid, 0). Если вызов преуспевает, процесс существует; если он вернется ESRCH это не так. Это, естественно, связано с неизбежными условиями гонки, которые в действительности намного меньше, чем в теории. Менее единообразные способы считывания файловой системы/proc (если у нее есть ОС), которая больше работает, равна одной и той же вещи и по-прежнему подчиняется тем же условиям гонки.

Обратите внимание, что метод блокировки файлов pid может быть двухуровневым. То есть, текущий процесс создает файл, блокирует его и записывает его pid. Он удерживает блокировку в течение всего времени ее запуска, и, таким образом, это в значительной степени устраняет вышеупомянутую потребность в запросе того, запущен ли процесс, потому что, если процесс завершится, блокировка файла будет автоматически выпущена, даже если файл все еще существует. Логика выглядит следующим образом:

if file exists 
    if can get lock 
     prev instance died unnaturally 
     continue with this new process 
    else 
     instance already running 
else 
    good to go, continue with new process 

Эта техника также имеет условия гонки.

Я не помню достаточно Java, чтобы сказать, имеет ли он обертки для kill или файл блокировки системных вызовов, как flock, lockf и fcntl, необходимых для реализации этой схемы.

+0

У нас есть другое приложение, закодированное в python, которое делает именно это. Мне просто нужно было выяснить способ получения определенного ПИД-кода более чистым способом. – ElCapitaine

+0

'kill' - ваш лучший и самый легкий из всех немного ошибочных вариантов. Опять же, вам действительно не нужно это делать, если вы заблокируете файл. – Duck

+0

Хорошо, большое спасибо. – ElCapitaine

3

Следующий код определяет, выполняется ли процесс с указанным pid. Он был протестирован на Windows 7 и Ubuntu 13. В Windows он использует apache commons-exec для запуска списка задач и определяет, нашли ли они указанный pid на основе кода выхода. Он преодолевает тот факт, что tasklist всегда возвращает 0, связывая результат с findstr. На linux он использует ps, чтобы делать то же самое. Он также подавляет регистрацию дочернего процесса stdout.

public static boolean isProcessRunning(int pid, int timeout, TimeUnit timeunit) throws java.io.IOException { 
    String line; 
    if (OS.isFamilyWindows()) { 
     //tasklist exit code is always 0. Parse output 
     //findstr exit code 0 if found pid, 1 if it doesn't 
     line = "cmd /c \"tasklist /FI \"PID eq " + pid + "\" | findstr " + pid + "\""; 
    } 
    else { 
     //ps exit code 0 if process exists, 1 if it doesn't 
     line = "ps -p " + pid; 
      //`-p` is POSIX/BSD-compliant, `--pid` isn't<ref>https://github.com/apache/storm/pull/296#discussion_r20535744</ref> 
    } 
    CommandLine cmdLine = CommandLine.parse(line); 
    DefaultExecutor executor = new DefaultExecutor(); 
    // disable logging of stdout/strderr 
    executor.setStreamHandler(new PumpStreamHandler(null, null, null)); 
    // disable exception for valid exit values 
    executor.setExitValues(new int[]{0, 1}); 
    // set timer for zombie process 
    ExecuteWatchdog timeoutWatchdog = new ExecuteWatchdog(timeunit.toMillis(timeout)); 
    executor.setWatchdog(timeoutWatchdog); 
    int exitValue = executor.execute(cmdLine); 
    // 0 is the default exit code which means the process exists 
    return exitValue == 0; 
} 
+0

Спасибо за проверку на подход PID, рекомендованный здесь. Я оказался вынужден использовать такой apporach в python. https://stackoverflow.com/questions/43274476/is-there-a-way-to-check-if-a-subprocess-is-still-running С уважением – 99Sono

1

См. Ниже, чтобы скопировать/вставить пример.

Булевский метод isStillAllive (...) получит в качестве параметра идентификатор процесса (pid). Вызов метода довольно общий и предназначен для обертывания логики, зависящей от устройства, для решения одной и той же проблемы в Windows/Linux/Unix, например, в операционных системах.

public boolean isStillAllive(String pidStr) { 
    String OS = System.getProperty("os.name").toLowerCase(); 
    String command = null; 
    if (OS.indexOf("win") >= 0) { 
     log.debug("Check alive Windows mode. Pid: [{}]", pidStr); 
     command = "cmd /c tasklist /FI \"PID eq " + pidStr + "\"";    
    } else if (OS.indexOf("nix") >= 0 || OS.indexOf("nux") >= 0) { 
     log.debug("Check alive Linux/Unix mode. Pid: [{}]", pidStr); 
     command = "ps -p " + pidStr;    
    } else { 
     log.warn("Unsuported OS: Check alive for Pid: [{}] return false", pidStr); 
     return false; 
    } 
    return isProcessIdRunning(pidStr, command); // call generic implementation 
} 

Фактический вызов системы делегирован isProcessIdRunning().Этот метод будет вызывать предварительно запрограммированную зависимую от системы команду в общем виде, и результат, полученный из системы, потребляется и анализируется по строкам. Если хотя бы одна из строк ответа содержит pid, мы интерпретируем это как успех.

private boolean isProcessIdRunning(String pid, String command) { 
    log.debug("Command [{}]",command); 
    try { 
     Runtime rt = Runtime.getRuntime(); 
     Process pr = rt.exec(command); 

     InputStreamReader isReader = new InputStreamReader(pr.getInputStream()); 
     BufferedReader bReader = new BufferedReader(isReader); 
     String strLine = null; 
     while ((strLine= bReader.readLine()) != null) { 
      if (strLine.contains(" " + pid + " ")) { 
       return true; 
      } 
     } 

     return false; 
    } catch (Exception ex) { 
     log.warn("Got exception using system command [{}].", command, ex); 
     return true; 
    } 
} 
+1

Возможно, было бы хорошо объяснить, что этот код делает для решения проблемы –

+0

благодарит за советом. Добавлено объяснение. – aprodan

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