2010-09-22 2 views
2

Я написал программу, которая вызывает системную команду изнутри:Как включить ctrl-c/ctrl + break после вызова системы?

#include <stdlib.h> 

int main(void) 
{ 
    while(1) 
    { 
     system("ls 2>&1 1>/dev/null"); // comment this line out to enable ctrl+break 
    } 

    return 0; 
} 

Однако, когда он работает, CTRL + C и CTRL + нарушит больше не работает и, как представляется, игнорируются.

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

Есть ли способ заставить его работать так, как я хочу? Должен ли я изменить архитектуру для выполнения какого-то вида fork/exec?

+0

В коде, который вы опубликовали выше, вполне вероятно, что цикл вращается так сильно, что никогда не будет возможности обработать сигнал. Это ваш настоящий код? –

+0

Вы рассматривали сценарий bash/shell как решение? – zengr

+0

@zengr: Я взаимодействую с несколькими библиотеками, поэтому bash не будет работать. – Martin

ответ

5

От POSIX specification for system():

система() функция игнорирует SIGINT и SIGQUIT сигналы и блокирует сигнал SIGCHLD, во время ожидания команды для завершения. Если это может заставить приложение пропустить сигнал, который бы его убил, тогда приложение должно проверить возвращаемое значение от system() и принять любое действие, соответствующее приложению, если команда завершена из-за приема сигнала.

Итак, чтобы правильно реагировать на сигналы, вам необходимо проверить возвращаемое значение system().

система() возвращает статус завершения командного интерпретатора языка в формате, заданном waitpid()

и документы о waitpid() ссылаться на документы для wait(), которые инструктируют использовать следующие макросы чтобы выяснить, почему процесс вышел:

  • WIFEXITED (stat_val)
    Вычисляет ненулевое значение, если статус был возвращен для дочернего процесса, который завершился нормально.
  • WEXITSTATUS (stat_val)
    Если значение WIFEXITED (stat_val) отличное от нуля, этот макрос оценивает 8 бит младшего порядка аргумента состояния, который дочерний процесс передал _exit() или exit(), или значение, возвращаемое дочерним процессом из main().
  • WIFSIGNALED (stat_val)
    Оценивает ненулевое значение, если статус был возвращен для дочернего процесса, который завершился из-за получения сигнала, который не был обнаружен (см.).
  • WTERMSIG (stat_val)
    Если значение WIFSIGNALED (stat_val) отличное от нуля, этот макрос оценивает номер сигнала, вызвавшего завершение дочернего процесса.
  • WIFSTOPPED (stat_val)
    Оценивает ненулевое значение, если статус был возвращен для дочернего процесса, который в настоящее время остановлен.
  • WSTOPSIG (stat_val)
    Если значение WIFSTOPPED (stat_val) отличное от нуля, этот макрос оценивает номер сигнала, из-за которого дочерний процесс останавливается.
  • WIFCONTINUED (stat_val)
    Оценивает ненулевое значение, если статус был возвращен для дочернего процесса, который продолжался с остановки управления заданием.

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

#include <stdlib.h> 
#include <stdio.h> 

int main(void) 
{ 
    while(1) 
    { 
     int result = system("ls 2>&1 1>/dev/null"); 
     if (WIFEXITED(result)) { 
      printf("Exited normally with status %d\n", WEXITSTATUS(result)); 
     } else if (WIFSIGNALED(result)) { 
      printf("Exited with signal %d\n", WTERMSIG(result)); 
      exit(1); 
     } else { 
      printf("Not sure how we exited.\n"); 
     } 
    } 

    return 0; 
} 

И если вы запустите его, вы получите:

 
$ ./sys 
Exited normally with status 0 
Exited normally with status 0 
Exited normally with status 0 
Exited normally with status 0 
Exited normally with status 0 
Exited normally with status 0 
^CExited with signal 2 
+0

@pmg исправлено, чтобы указать POSIX. –

+0

Вызывает ли вызов system() немедленно, когда выдается SIGINT? Я думаю, что это то, с чем столкнулись ОП. –

+0

@San Jacinto Да, процесс, порожденный 'system', получает' SIGNINT' нормально, и если он его не поймает, он будет убит, а 'system' вернется немедленно. Если вам нужно иметь возможность обрабатывать 'SIGINT' самостоятельно, даже если ребенок его ловит, вам нужно будет использовать дополнительный процесс, как вы предложили. –

2

По IEEE Std 1003.1-2008 (POSIX):

  • system() функция должна вести себя так, как будто дочерний процесс были созданы с использованием fork() ...

  • system() функция должна игнорировать SIGINT и SIGQUIT сигналы и должны блокировать сигнал SIGCHLD, ожидая завершения команды. Если это может заставить приложение пропустить сигнал, который бы его убил, тогда приложение должно проверить возвращаемое значение от system() и принять любое действие, соответствующее приложению, если команда прекращена из-за приема сигнала.

  • Функция system() не должна возвращаться до завершения дочернего процесса.

1

Из комментария Сан-Хасинто выше:

system() по существу вилки, блокирует родительский элемент и игнорирует определенные сигналы в дочернем элементе, в соответствии с спецификациями POSIX. Вы можете обойти это, сначала создав другой процесс для блокировки системы(). Это оставляет исходный процесс (бабушка и дедушка процесса, в котором работает оболочка), чтобы принимать сигналы об удалении.

#include <stdlib.h> 
#include <unistd.h> 
#include <wait.h> 

int main(void) 
{ 
    pid_t pid; 

    while(1) 
    { 
     pid = fork(); 

     if(pid > 0) // parent 
     { 
      wait(0); 
     } 
     else if(pid == 0) // child 
     { 
      system("ls 2>&1 1>/dev/null"); 
      return 0; 
     } 
     else // could not fork 
     { 
      return 1; 
     } 
    } 

    return 0; 
} 

На первый взгляд кажется, что он делает то, что мне нужно.

+0

Это немного сложнее, чем я предложил в своем ответе. Вам не нужно отрывать отдельный процесс; все, что вам нужно сделать, это проверить возвращаемое значение 'system'. Я обновил свой ответ на примере того, как это сделать. –

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