Перехват сигнала Ctrl + C вызывает исключение «Диспетчер заданий выключен» - PullRequest
7 голосов
/ 05 июня 2019

Я пытаюсь добавить поддержку сигналов (особенно для Ctrl + C).Мой инструмент написан на Java, и я хотел бы выполнить очистку, когда Ctrl+C пойман.Мой основной файл - это Приложение, и в нем есть следующий код:

if (ArgDefinitions.getInstance().hasOption(ArgNames.EXECUTE)) {
    performShutdownHooks(); 
    preformRun();
}

Приложение анализирует параметры пользователя и запускает правильный метод.Поэтому, когда пользователь использует опцию execute и нажимает Ctrl+C, я бы хотел, чтобы программа остановила и очистила область.Я добавил метод performShutdownHooks для обработки сигнала, и он выглядит следующим образом:

private void performShutdownHooks() {
    Runtime.getRuntime().addShutdownHook(new Thread() {
        @Override
        public void run() {
            performCleanup();
        }
    });
}

Он делает то, что я хочу - если я запускаю инструмент и убиваю его во время работы, он выполняет очистку(он запускает специальную команду в фоновом режиме).Проблема возникает, когда я не прекращаю это.Я получаю следующее исключение:

Exception in thread "Thread-2" java.lang.IllegalStateException: Job manager has been shut down.
        at org.eclipse.core.internal.jobs.JobManager.schedule(JobManager.java:1104)
        at org.eclipse.core.internal.jobs.InternalJob.schedule(InternalJob.java:427)
        at org.eclipse.core.runtime.jobs.Job.schedule(Job.java:436)
        at glichautil.CommandExecutor.runCommandInBackground(CommandExecutor.java:134)
        at glicha.core.Application.performCleanup(Application.java:869)
        at glicha.core.Application.access$0(Application.java:838)
        at glicha.core.Application$1.run(Application.java:985)

Я думаю, что performShutdownHooks работает в конце, хотя я не пытался его убить.Может быть, что-то еще убивает это, но это не должно произойти, потому что, если я закомментирую вызов метода performShutdownHooks(), он будет работать регулярно (без каких-либо исключений).Это заставляет меня поверить, что по какой-то причине метод performShutdownHooks запускается, хотя я не нажимал Ctrl+C.Есть ли что-то, что мне нужно добавить в метод performShutdownHooks, чтобы решить это?Может, я что-то упустил из-за addShutdownHook?Если это правильное объяснение проблемы, то я думаю, что если бы я мог каким-то образом разобрать его, запустите в конце, то это решило бы проблему.Также возможно, что некоторые другие потоки, используемые в коде, уничтожаются и по какой-то причине выполняют этот метод.

EDIT : я думаю, что мне удалось понять, почему онработает такПрежде чем войти в мой метод ShutdownHooks, он печатает:

Job found still running after platform shutdown.
Jobs should be canceled by the plugin that scheduled them during shutdown: glicha.testmanager.HandleParallelJobs.

Я думаю, это то, что вызывает ShutdownHooks.Проблема в том, что я понятия не имею, как ее решить.Я прочитал из документов:

Виртуальная машина Java отключается в ответ на два вида событий:

  • Программа завершается нормально, когда последний не-deemon поток завершается, или когда вызывается метод выхода (эквивалентно System.exit), или

  • Виртуальная машина прерывается в ответ на пользовательское прерывание, такое как ввод Ctrl + C или общесистемное событие, такое как выход пользователя из системы или завершение работы системы.

Итак, я предполагаю, что когдаплагин выключается, он вызывает ShutdownHooks (поправьте меня, если я ошибаюсь).Проблема в том, что я не понимаю, как я могу разделить эти две возможности.Я хотел бы поймать только сигналы и выполнить очистку, но я не хочу делать это, если один из ВМ выключается.Есть идеи, как мне подойти к этому вопросу?

Ответы [ 2 ]

0 голосов
/ 14 июня 2019

Вы можете переопределить метод SecurityManager checkExit(int status) - он работает, если System.exit(status) вызывается где-либо явно, - однако, он не устанавливает статус, когда приложение выходит «нормально» (без активных потоков) или ошибка убивает ВМ.

System.setSecurityManager(new ExitMonitorSecurityManager());
Runtime.getRuntime().addShutdownHook(new Thread(new MyShutdownHook()));

private static class ExitMonitorSecurityManager extends SecurityManager {

        @Override
        public void checkPermission(Permission perm) {
            //Something;
        }

        @Override
        public void checkPermission(Permission perm, Object context) {
            //Something
        }

        @Override
        public void checkExit(int status) {
            System.out.println("Setting exit value via security manager...");
            MyShutdownHook.EXIT_STATUS = status;
        }
    }

    private static class MyShutdownHook implements Runnable {

        public static Integer EXIT_STATUS;

        public void run() {

            System.out.println("In MyShutdownHook - exit status is " + EXIT_STATUS);
        }
    }
0 голосов
/ 08 июня 2019

Одна из распространенных проблем, связанных с отключением, заключается в том, что не существует гарантированного порядка отключения.Я предполагаю, что в вашем случае Schedule фреймворк уже может иметь хук отключения самостоятельно, который уже выполняет очистку (остановка задач).

Javadoc, связанный с перехватчиками завершения работы, несколько объясняет, что вы не можете полагаться на существование other resources, поскольку они, возможно, уже были отключены.

Теперь, когда вы пытаетесь сделать это в своем завершении работыловушка, вы можете получить вышеупомянутую ошибку, в зависимости от порядка выполнения ловушек отключения.


Все это не совсем то, что вы просили, но я думаю, что у вас может не бытьпроблема вообще.Я бы предпочел обсудить следующие вещи

  • В чем причина, по которой вы хотите, чтобы сначала был отключен хук отключения?
  • Зачем (вам это нужно)чтобы остановить запущенные задания самостоятельно?

Возможно, вы захотите добавить код, который вы запускаете при выполнении очистки, к своему вопросу.Согласно имеющейся у меня информации, вы, возможно, захотите отключить то, что уже было отключено.


Если вы все еще хотите сделать перехват Singal, на самом деле есть способ, , но я бы не сталЯ рекомендую это .По этой ссылке https://www.javaspecialists.eu/archive/Issue043.html, вы можете использовать класс Signal пакета sun.misc. *.

Пакет sun.misc содержит только неофициальные API, которые могут быть удалены без дальнейшего уведомленияв любое время.Похоже, не существует официального API, который бы поддерживал ваш вариант использования (по крайней мере, насколько мне известно).

...