Что касается фоновых процессов с использованием fork() и дочерних процессов в моей фиктивной оболочке

StackOverflow https://stackoverflow.com/questions/8319484

  •  25-10-2019
  •  | 
  •  

Вопрос

Я пытаюсь создать простую программу оболочки на C.Что мне нужно, так это предоставить пользователю приглашение, в котором он может запускать другие локальные программы.Я могу прекрасно выполнить эту часть, используя fork(), в котором родительский процесс ожидает() дочернего процесса, а дочерний execvp() — программу.

Однако, если к концу пользовательской команды добавляется символ «&», мне нужно, чтобы их программа работала в фоновом режиме, то есть мне нужно, чтобы родитель НЕ ждал дочернего процесса, а вместо этого немедленно возвращал приглашение пользователю, позволяя фоновому процессу продолжать работу, но не позволяя ему отображать что-либо на экране.Я просто хочу иметь возможность проверить, что он все еще существует, с помощью команды ps.

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

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

Это моя реализация кода, которая, я уверен, совершенно неверна.Мне просто интересно, является ли вся эта история с внуками тем путем, по которому мне нужно идти, и если да, то что не так с моим кодом?

36 int main(int argc, char *argv[])
37 {
38     char buffer[512];
39     char *args[16];
40     int background;
41     int *status;
42     size_t arg_ct;
43     pid_t pid;
44 
45     while(1)
46     {
47         printf("> ");
48         fgets(buffer, 512, stdin);
49         parse_args(buffer, args, 16, &arg_ct);
50 
51         if (arg_ct == 0) continue;
52 
53         if (!strcmp(args[0], "exit"))
54         {
55             exit(0);
56         }
57 
58         pid = fork();  //here I fork and create a child process
61 
62         if (pid && !background)  //i.e. if it's the parent process and don't need to run in the background (this is the part that seems to work)
63         {
64             printf("Waiting on child (%d).\n", pid);
65             pid = wait(status);
66             printf("Child (%d) finished.\n", pid);
67         }
68         else
69         {
70             if (background && pid == 0) { //if it's a child process and i need to run the command in background
71                
72                 pid = fork(); //fork child and create a grandchild
73                 if (pid) exit(0); //exit child and orphan grandchild
74                 
75                 execvp(args[0], args); //orphan execs the command then exits
76                 exit(1);
77 
78             } else exit(0);
79         }
80     }
81     return 0;
82 }

P.S. Чтобы внести ясность: мне нужно, чтобы процесс, который я запускаю в фоновом режиме, никогда больше не издавал ни звука, даже если у него есть бесконечный цикл операторов печати или что-то в этом роде.Я просто хочу убедиться, что он все еще работает в фоновом режиме через ps -a или что-то в этом роде.

Извините за запутанное объяснение, я просто не знаю, как объяснить это лучше.

заранее спасибо

П.П.С. Я реализую это так, чтобы каждая последующая команда определяла логическое значение «фона», извините за путаницу.

Это было полезно?

Решение

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

Вместо этого способ дублировать поведение & в существующих оболочках нужно вызвать fork(), затем в дочернем вызове setpgid(0, 0); поместить ребенка в новую группа процессов.Родитель просто продолжает (возможно, после печати PID ребенка) - не звонит wait().

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

Если группа фоновых процессов попытается прочитать данные с терминала, ей будет отправлен сигнал, чтобы остановить это.Вывод на терминал по-прежнему разрешен - это нормально (попробуйте ls & в вашей обычной оболочке).Для реализации fg в вашей оболочке, вам понадобится tcsetpgrp() функция для изменения группы процессов переднего плана.

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

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top