То, что на самом деле делает код, принимает входные данные от родительского процесса, отправляет его дочернему процессу через канал. Детский процесс меняет его, а затем отправляет обратно родительскому каналу через другой канал. В коде нет функции waitpid()
или wait()
.
Вопрос в том, как здесь работает процесс переключения? Как работают функции write()
и read()
?
Вот код:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <iostream>
#define li long int
using namespace std;
void ReverseAString(char input[])
{
li length = strlen(input),i;
char hold;
for(i=0;i<length/2;i++)
{
hold = input[i];
input[i] = input[length-(i+1)];
input[length-(i+1)] = hold;
}
}
int main()
{
pid_t ChildOrParentId;
int fifoParent[2],fifoChild[2],in;
if(pipe(fifoParent)==-1)
{
cout<<"Problem in creating Parent Pipe"<<endl;
perror("Parent Pipe");
exit(1);
}
if(pipe(fifoChild)==-1)
{
cout<<"Problem in creating Child Pipe"<<endl;
perror("Child Pipe");
exit(1);
}
ChildOrParentId = fork();
if(ChildOrParentId==0)
{
char buf[100],collected[100];
close(fifoParent[0]);
close(fifoChild[1]);
in = 0;
while(read(fifoChild[0],buf,1)>0)
{
collected[in]=buf[0];
in++;
}
collected[in]=0;
cout<<"Read from Child "<<collected<<endl;
ReverseAString(collected);
cout<<"After Reversing: "<<collected<<endl;
write(fifoParent[1],collected,sizeof(collected));
close(fifoParent[1]);
}
else
{
char buf[100],collected[100];
close(fifoParent[1]);
close(fifoChild[0]);
in = 0;
cout<<"Enter a string: ";
gets(buf);
write(fifoChild[1],buf,sizeof(buf));
close(fifoChild[1]);
while(read(fifoParent[0],buf,1)>0)
{
collected[in] = buf[0];
in++;
}
collected[in] = 0;
cout<<"Read from Parent "<<collected<<endl;
}
return 0;
}
Окно вывода выглядит следующим образом:
Enter a string: abc // abc input given
Read from child abc
After reversing: cba
Read from parent cba
Обычно read
на пустых трубах до тех пор, пока данные не станут доступными, записав на конец записи трубы.
Таким образом, дочерний процесс не может продолжать выполнение этой строки до тех пор, пока не получит данные от родителя; он блокирует его ожидание:
while(read(fifoChild[0],buf,1)>0)
После того, как он прочитал строку, она просыпается, меняет ее и записывает обратно родительскому. Родитель также может быть заблокирован, когда достигнет следующей строки, ожидая, пока дочерний процесс напишет обратную строку:
while(read(fifoParent[0],buf,1)>0)
Поведение блокировки read
похоже на поведение блокировки wait
или waitpid
, но оно ожидает, что данные будут поступать в дескриптор файла, а не ждать, пока дочерний процесс изменит статус.
В общем случае родительский и дочерний процессы выполняются одновременно, за исключением случаев, когда один или оба блокируются при системном вызове.
В тот момент, когда вы вызываете fork()
, создается второй процесс, и оба процесса находятся в этой точке кода. Единственный способ узнать, являетесь ли вы новым дочерним процессом или исходным родительским процессом, - это посмотреть на возвращаемое значение fork()
. В документации вы можете видеть, что если fork()
возвращает 0, вы находитесь в дочернем процессе. Итак, в основном, then
блок if(ChildOrParentId==0)
работает только в дочернем процессе, а блок else
работает только в родительском процессе.
Остальное объяснение довольно прямолинейно, если вы посмотрите на эти два блока как разные программы. Родительский блок запрашивает строку, отправляет ее ребенку, ждет, когда ребенок отправит что-то обратно, затем распечатает то, что отправил ребенок. Между тем, дочерний блок ждет чего-то от родителя, распечатывает то, что получает, меняет его и печатает, а затем отправляет обратную строку обратно родительскому.