Недавно я научился делать всю эту штуку fork/exec/wait
и в итоге написал некоторый код, который выглядел урезанным следующим образом:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main() {
pid_t x = fork();
if (x == 0) {
execlp("sqlite3", "sqlite3");
printf("exec failed\n");
} else {
wait(NULL);
printf("Hi\n");
}
}
Это работает довольно хорошо и фактически приводит к открытию оболочки sqlite3
, но есть одна проблема. Если вы Ctrl + C
выходите из оболочки sqlite3
, то она также завершает родительский процесс, и строка printf("Hi\n")
никогда не запускается.
Я предположил, что это произошло из-за того, что SIGINT распространяется на родительский процесс, и после дальнейшего изучения я прочитал, что SIGINT завершит все процессы в одной и той же группе, а это означает, что поскольку родительский и дочерний элементы используют одну и ту же группу, они оба прекращено.
Я попытался исправить это, пытаясь вызвать setpgid
следующим образом:
int main() {
pid_t x = fork();
if (x == 0) {
setpgid(getpid(), getpid()); // <-- Added in this line
execlp("sqlite3", "sqlite3");
printf("exec failed\n");
} else {
wait(NULL);
printf("Hi\n");
}
}
который работал нормально, но это сломало подсказку sqlite3
. Более того, Ctrl + C
все равно убил родителя в этом случае. Я решил еще больше сузить круг, а потом нашел кое-что странное и запутался. Если просто поместить вызов getpid()
в вилку, вызов execlp()
потерпит неудачу.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main() {
pid_t x = fork();
if (x == 0) {
getpid(); // <--- just adding this in makes it fail
execlp("sqlite3", "sqlite3");
printf("exec failed\n");
} else {
wait(NULL);
printf("Hi\n");
}
}
и даже не только для sqlite3
, но и для простых вещей, таких как execlp("ls", "ls")
(хотя это может быть не связано с исходным вопросом).
Я немного не в себе, и мне было интересно, может ли кто-нибудь указать мне правильное направление. Я не совсем уверен, что делать дальше.
- Я на OSX 10.11 и компилирую с clang.
clang --version
: Apple LLVM версии 8.0.0 (clang-800.0.42.1)
Ctrl + C
на передний план? Кроме того, почему это не так, когда я делаюexeclp("bash", "bash")
? Это прекрасно справляется сCtrl + C
. - person m0meni   schedule 08.11.2016sqlite3
— это просто какой-то другой процесс, который использует тот же канал стандартного ввода. Вы можете обработать ctrl+c в своей программе C и отправить sqlite3 SIGTERM или использовать Ctrl+D для отправки EOF на стандартный ввод, который sqlite3 подберет и интерпретирует как конец потока стандартного ввода. - person Colonel Thirty Two   schedule 08.11.2016execlp("bash", "bash")
? Это прекрасно справляется сCtrl + C
. - person m0meni   schedule 08.11.2016execlp("bash", "bash", NULL);
--NULL
требуется для завершения списка аргументов дляexecl()
,execlp()
иexecle()
. Затем, если вы хотите обрабатывать Ctrl+C в родительском процессе, просто установите обработчик сигнала, который будет пересылать сигналSIGINT
дочернему процессу. - person Nominal Animal   schedule 08.11.2016