#c #linux #operating-system
#c #linux #операционная система
Вопрос:
Мне было поручено создать ровно 6 процессов с использованием языка c и команды fork(), а затем перевести все 6 в режим ожидания с помощью sleep() на минуту или две. Сложнее всего то, что нам вообще не разрешено использовать какие-либо циклы, и всего 3 вызова fork() . Мне удалось успешно создать 8, но это слишком много. Итак, мне было интересно, можно ли разветвлять или уничтожать определенные процессы.Я попробовал кое-что, что видел здесь, но это дает мне 8 процессов, а не 6
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
int main()
{
/* fork a child process */
pid_t child = fork();
pid_t parent = getpid();
fork(); //2
if (fork() > 0) {//now we have 2 processes
//only the parent calls this fork because of the if, so we have 3 processes
fork(); //all 3 processes calls this fork, so we have 6 processes
wait(NULL);
printf("I am the child process");
printf("my PID = %d ",child);
printf("I am the parent process. My PID is %dn", parent);
wait(NULL);
}
else if (child < 0) { /* error occurred */
fprintf(stderr, "Fork Failed");
return 1;
}
}
я получаю:
I am the child processmy PID = 22150 I am the parent process. My PID is 22149
I am the child processmy PID = 22150 I am the parent process. My PID is 22149
I am the child processmy PID = 0 I am the parent process. My PID is 22150
I am the child processmy PID = 22150 I am the parent process. My PID is 22149
I am the child processmy PID = 0 I am the parent process. My PID is 22150
I am the child processmy PID = 0 I am the parent process. My PID is 22150
I am the child processmy PID = 0 I am the parent process. My PID is 22150
I am the child processmy PID = 22150 I am the parent process. My PID is 22149
Комментарии:
1. Возвращаемое значение
fork()
сообщает вам, находитесь ли вы в родительском или дочернем процессе, и (только в родительском), было ли разветвление успешным. Подробнее читайте его документацию. Вы можете использовать это для различения процессов, чтобы выбрать, какие из них должны развиваться дальше.2. Вы вызываете
fork
4 раза. Возможно, вы не намеревались вызыватьfork
при инициализации переменнойchild
. Если вы удалите этот вызов, ваша логика кажется правильной, и вы получите 6 процессов, как и требовалось.3. Но обратите внимание на двусмысленность во фразе «вызов fork 4 раза». В вашем коде есть 4 разных экземпляра токена «fork», но всего он вызывается 11 раз.
4. Хотя ваша программа выдает вам 8 строк вывода, у вас есть 12 процессов. Не все из них выдают выходные данные.
Ответ №1:
Вы можете получить дерево с 6 новыми процессами ( 1 исходный), создав третью вилку только в 3 из четвертых процессов, которые у вас будут после 1-го 2 вилки.
#include <unistd.h>
#include <stdio.h>
/*
Process tree:
/
/
//
/
/
*/
int main()
{
_Bool descended_from_parent, descended_from_child;
pid_t pid;
if(0>(pid=fork())) return perror("fork"),1;
descended_from_parent = pid == 0;
if(0>(pid=fork())) return perror("fork"),1;
descended_from_child = pid == 0;
if(!descended_from_parent || descended_from_child) if(0>(pid=fork())) return perror("fork"),1;
sleep(60);
}
// run as `./a.out amp;` and then do `ps --forest` to see the process tree
Комментарии:
1. Тогда @bruno, должно быть, неправильно понял это. Исправлено. Спасибо.
Ответ №2:
#include <stdio.h>
#include <unistd.h>
int main(void) {
int f1 = -1, f2 = -1, f3 = -1;
printf("1 process running -- f1: %d; f2: %d; f3: %dn", f1, f2, f3);
sleep(1); // try to prevent print lines mangling
f1 = fork(); // assume it worked
printf("2 processes running -- f1: %d; f2: %d; f3: %dn", f1, f2, f3);
sleep(1); // try to prevent print lines mangling
f2 = fork(); // assume it worked for the 2 running processes
printf("4 processes running -- f1: %d; f2: %d; f3: %dn", f1, f2, f3);
sleep(1); // try to prevent print lines mangling
if ((f1 > 0) || (f2 > 0)) f3 = fork(); // assume it worked for the 3 selected processes
printf("7 processes running -- f1: %d; f2: %d; f3: %dn", f1, f2, f3);
return 0;
}
Комментарии:
1. Вы не можете вызывать
printf
followed byfork
без прерыванияfflush
и ожидать разумного результата. Вы не должны полагаться на буферизацию стандартного вывода. (Выполните это с обычным файлом для стандартного вывода, и вы увидите совсем другой результат, чем когда стандартный вывод является tty.)
Ответ №3:
Ваша логика просто прекрасна. Я подозреваю, что путаница связана с инициализацией переменной child
, в которой вы вызываете fork
в первый раз. Кроме того, ваш вывод нечетный, и вы не сообщаете о результатах для каждого процесса. Простой рефакторинг вашего кода на что-то более простое показывает, что ваша логика верна:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
int
main(void)
{
fork();
if( fork() == 0 ) {
fork();
}
printf("PID = %dn", getpid());
}
Приведенный выше в основном ваш код, и он выдает ровно 6 строк вывода, по желанию. Единственное реальное отличие заключается в том, что я удалил ложный первоначальный вызов fork
и переместил printf в нужное место. В вашем коде у вас есть 4 процесса, когда в вашем комментарии утверждается, что их всего 2 (из-за ложной инициализации fork ), и все 4 из них снова разветвляются, чтобы сделать 8. Из этих 8 4 из них переформируются, чтобы дать вам в общей сложности 12, из которых только 8 печатают какие-либо выходные данные. (4, которые были разветвлены, и их новые дочерние элементы.) Однако выходные данные, которые они выдают, наиболее необычны и не отражают фактический pid процесса, записывающего выходные данные. Они просто показывают идентификаторы pid, которые были после начальной вилки при инициализации child
.
Ответ №4:
Самый простой способ
#include <stdio.h>
int main()
{
fork() amp;amp; fork();
fork();
printf("%d %dn",getpid(),getppid());
sleep(1);
}
Комментарии:
1. Пожалуйста, добавьте некоторые пояснения к вашему ответу. В частности, в чем преимущество
fork() amp;amp; fork();
более двухfork();
операторов?