Нужна консультация fork, pipe, execvp
От: Saddam Россия http://saddam.narod.ru
Дата: 13.03.17 15:45
Оценка:
Коллеги, добрый вечер!
Изучаю многопоточное программирование в линуксе. Пробую написать аналог пайпа.
Код ниже. Никак не получается запустить больше двух процессов. Мастер зависает наглухо.
Туплю... Весь день не могу победить проблему. Ткните носом, буду очень признателен....

#include <iostream>
#include <fstream>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <vector>
#include <array>
//#include <algorithm>
//#include <functional>
//#include <cctype>
//#include <locale>
#include <string.h>
#include <sys/wait.h>

using namespace std;

void parce(char *s, char delim, std::vector<char *> &CmdList)
{
    unsigned int l=strlen(s);
    unsigned int i=0;
    CmdList.push_back(s);
    //while (s[strlen(s)-1]==' ') s[strlen(s)-1]=0;
    for (i=0;i<l;i++)
        if (s[i]==delim)
        {
            s[i]=0;
            i++;
            while (s[i]==' ') {s[i]=0;i++;}
            if (strlen(&s[i])) CmdList.push_back(&s[i]);
            while (s[strlen(&s[i])-1]==' ') s[strlen(&s[i])-1]=0;
    }
}
int main() {
    std::filebuf fb;
    fb.open ("/home/saddam/Pipe.log",std::ios::out);
    std::ostream os(&fb);
    std::vector<char *> CmdList;
    char cmdLine[1024];
    int iChildPID=0, subCount=0;
    //cin>>cmdLine;
    strcpy(cmdLine,"who | sort | uniq -c | sort -nk1");
    //strcpy(cmdLine,"who | sort -nk1");
    parce(cmdLine,'|',CmdList);
    std::vector<int *> Pipes;
    for (unsigned int i=0;i<CmdList.size()-1;i++)
    {
        int *Pipe=new int[2];
        Pipes.push_back(Pipe);
        if (0<pipe(Pipes[i]))
        {
            cout << "Pipe error" << endl;
            return errno;
        }
        os << "Pipe" << i <<": " << Pipes[i][0]<<", "<<Pipes[i][1]<<endl;
    }
    int fd = 0;
    while (!CmdList.empty())
    {
        std::vector<char *> ParamList;
        parce(CmdList.front(),' ',ParamList);
        ParamList.push_back(NULL);
        if (!(iChildPID=fork()))
        {
            if (CmdList.size()>1)
            {
                dup2(Pipes[subCount][1],1);//O_CLOEXEC
                close(Pipes[subCount][0]);
                Pipes[subCount][1]=1;
                os<<getpid()<<" Pipe(>)"<<subCount<<": "<< Pipes[subCount][0]<<", "<<Pipes[subCount][1]<<endl;
            }
            else
            {
                fd = open("/home/saddam/result.out",   O_CREAT | O_RDWR );
                dup2(fd,1);
                os<<getpid()<<" File(>)\n";
            }
            if (subCount)
            {
                dup2(Pipes[subCount-1][0],0);
                Pipes[subCount-1][0]=0;
                close(Pipes[subCount-1][1]);
                os<<getpid()<<" Pipe(<)"<<subCount-1<<": "<< Pipes[subCount-1][0]<<", "<<Pipes[subCount-1][1]<<endl;
            }
            if (-1==execvp(CmdList.front(),ParamList.data()))
                return errno;
        }
        subCount++;
        cout <<" PID:"<<iChildPID<<" Count:"<<subCount<< endl;
        CmdList.erase(CmdList.begin());
    }
    int status=0;
    cout <<"Waiting for "<<subCount<< endl;
    int pid ;
    for (int i=1;i<subCount;i++)
    {
        cout <<"Waiting for "<<subCount-i<< endl;
        pid=wait(&status);
        cout <<"PID: "<<pid<<" terminated \n";
    }
    close(fd);
    cout <<"Master is finished!"<< endl; // prints !!!Hello World!!!
    fb.close();
    return 0;
}
- Вы знаете — жаль, просто по-человечески жаль Памелу Андерсон, которая никогда не сможет сыграть на баяне...
fork pipe execvp linux
Re: Нужна консультация fork, pipe, execvp
От: Masterspline  
Дата: 13.03.17 21:02
Оценка: 2 (1)
У тебя в массиве Pipes остаются файловые дескрипторы в открытом состоянии (причем как в детях, кроме тех fd, которые заменяются на stdin/out, так и в мастере, прием в нем все fd остаются открытыми), а их нужно закрыть. Иначе программа, читающая из канала не знает когда ей закончить, т.к. в каком-то процессе есть еще открытый файловый дескриптор от пишущего конца канала, хотя процесс, который писал уже завершился.

Т.е. происходит следующее (для "who | sort | uniq -c" ):

1. создаются дескрипторы для pipe в мастере, затем три ребенка (в которых тоже есть эти дескрипторы).
2. первый ребенок меняет и закрывает дескриторы Pipes[0], но оставляет открытыми Pipes[1], затем exec, который пишет и успешно заканчивает работу
3. второй ребенок меняет Pipes[1], но сохраняет Pipes[0] и читает что надо, но так как есть еще незакрытые копии файловых дескрипторов для нулевого pipe (в мастере и третьем ребенке), то его записывающий конец не закрыт и sort продолжает пытаться читать. Нужно закрыть все пишущие концы канала в мастере и других детях, чтобы при выходе "who" и закрытии им своего пишущего конца sort на читающем конце считал все, что есть и завершил чтение, т.к. данных больше нет, пишущий конец закрыт.

Вот мой пропатченный вариант:
  Исправленный код
#include <iostream>
#include <fstream>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <vector>
#include <array>
//#include <algorithm>
//#include <functional>
//#include <cctype>
//#include <locale>
#include <string.h>
#include <sys/wait.h>

using namespace std;

void parse(char *s, char delim, std::vector<char *> &CmdList)
{
    unsigned int l=strlen(s);
    unsigned int i=0;
    CmdList.push_back(s);
    //while (s[strlen(s)-1]==' ') s[strlen(s)-1]=0;
    for (i=0;i<l;i++)
    {
        if (s[i]==delim)
        {
            s[i]=0;
            i++;
            while (s[i]==' ') {s[i]=0;i++;}
            if (strlen(&s[i])) CmdList.push_back(&s[i]);
            while (s[strlen(&s[i])-1]==' ') s[strlen(&s[i])-1]=0;
        }
    }
}
int main() {
    std::filebuf fb;
    fb.open ("./Pipe.log",std::ios::out);
    std::ostream os(&fb);
    std::vector<char *> CmdList;
    char cmdLine[1024];
    int iChildPID=0, subCount=0;
    //cin>>cmdLine;
    strcpy(cmdLine,"who | sort | uniq -c | sort -nk1");
    //strcpy(cmdLine,"who | sort -nk1");
    parse(cmdLine,'|',CmdList);
    std::vector<int *> Pipes;
    for (unsigned int i=0;i<CmdList.size()-1;i++)
    {
        int *Pipe=new int[2];
        Pipes.push_back(Pipe);
        if ( pipe(Pipes[i]) < 0 )
        {
            cout << "Pipe error" << endl;
            return errno;
        }
        os << "Pipe" << i <<": " << Pipes[i][0]<<", "<<Pipes[i][1]<<endl;
    }
    int fd = 0;
    while (!CmdList.empty())
    {
        std::vector<char *> ParamList;
        parse(CmdList.front(),' ',ParamList);
        ParamList.push_back(NULL);
        if (!(iChildPID=fork()))
        {
            if (CmdList.size()>1)
            {
                dup2(Pipes[subCount][1],1);//O_CLOEXEC
                close(Pipes[subCount][0]);
                Pipes[subCount][1]=1;
                os<<getpid()<<" Pipe(>)"<<subCount<<": "<< Pipes[subCount][0]<<", "<<Pipes[subCount][1]<<endl;
            }
            else
            {
                fd = open("./result.out",   O_CREAT | O_RDWR );
                dup2(fd,1);
                os<<getpid()<<" File(>)\n";
            }
            if (subCount)
            {
                dup2(Pipes[subCount-1][0],0);
                Pipes[subCount-1][0]=0;
                close(Pipes[subCount-1][1]);
                os<<getpid()<<" Pipe(<)"<<subCount-1<<": "<< Pipes[subCount-1][0]<<", "<<Pipes[subCount-1][1]<<endl;
            }
            for( int it = 0; it < Pipes.size(); ++it )
            {
                if( it != subCount )
                {
                    close( close(Pipes[it][0]) );
                    close( close(Pipes[it][1]) );
                }
            }
            if (-1==execvp(CmdList.front(),ParamList.data()))
            {
                std::cerr << "error in execvp: " << strerror(errno) << std::endl;
                return errno;
            }
        }
        subCount++;
        cout <<" PID:"<<iChildPID<<" Count:"<<subCount<< endl;
        CmdList.erase(CmdList.begin());
    }
    for( int it = 0; it < Pipes.size(); ++it )
    {
        close( close(Pipes[it][0]) );
        close( close(Pipes[it][1]) );
    }
    int status=0;
    cout <<"Waiting for "<<subCount<< endl;
    int pid ;
    for (int i=1;i<subCount;i++)
    {
        cout <<"Waiting for "<<subCount-i<< endl;
        pid=wait(&status);
        cout <<"PID: "<<pid<<" terminated \n";
    }
    close(fd);
    cout <<"Master is finished!"<< endl; // prints !!!Hello World!!!
    fb.close();
    return 0;
}

  В виде патча
[сcode]
--- old.cpp 2017-03-13 23:59:27.729222560 +0300
+++ main.cpp 2017-03-13 23:59:11.217348891 +0300
@@ -15,13 +15,14 @@

using namespace std;

-void parce(char *s, char delim, std::vector<char *> &CmdList)
+void parse(char *s, char delim, std::vector<char *> &CmdList)
{
unsigned int l=strlen(s);
unsigned int i=0;
CmdList.push_back(s);
//while (s[strlen(s)-1]==' ') s[strlen(s)-1]=0;
for (i=0;i<l;i++)
+ {
if (s[i]==delim)
{
s[i]=0;
@@ -29,11 +30,12 @@
while (s[i]==' ') {s[i]=0;i++;}
if (strlen(&s[i])) CmdList.push_back(&s[i]);
while (s[strlen(&s[i])-1]==' ') s[strlen(&s[i])-1]=0;
+ }
}
}
int main() {
std::filebuf fb;
— fb.open ("/home/saddam/Pipe.log",std::ios::out);
+ fb.open ("./Pipe.log",std::ios::out);
std::ostream os(&fb);
std::vector<char *> CmdList;
char cmdLine[1024];
@@ -41,13 +43,13 @@
//cin>>cmdLine;
strcpy(cmdLine,"who | sort | uniq -c | sort -nk1");
//strcpy(cmdLine,"who | sort -nk1");
— parce(cmdLine,'|',CmdList);
+ parse(cmdLine,'|',CmdList);
std::vector<int *> Pipes;
for (unsigned int i=0;i<CmdList.size()-1;i++)
{
int *Pipe=new int[2];
Pipes.push_back(Pipe);
— if (0<pipe(Pipes[i]))
+ if ( pipe(Pipes[i]) < 0 )
{
cout << "Pipe error" << endl;
return errno;
@@ -58,7 +60,7 @@
while (!CmdList.empty())
{
std::vector<char *> ParamList;
— parce(CmdList.front(),' ',ParamList);
+ parse(CmdList.front(),' ',ParamList);
ParamList.push_back(NULL);
if (!(iChildPID=fork()))
{
@@ -71,7 +73,7 @@
}
else
{
— fd = open("/home/saddam/result.out", O_CREAT | O_RDWR );
+ fd = open("./result.out", O_CREAT | O_RDWR );
dup2(fd,1);
os<<getpid()<<" File(>)\n";
}
@@ -82,13 +84,29 @@
close(Pipes[subCount-1][1]);
os<<getpid()<<" Pipe(<)"<<subCount-1<<": "<< Pipes[subCount-1][0]<<", "<<Pipes[subCount-1][1]<<endl;
}
+ for( int it = 0; it < Pipes.size(); ++it )
+ {
+ if( it != subCount )
+ {
+ close( close(Pipes[it][0]) );
+ close( close(Pipes[it][1]) );
+ }
+ }
if (-1==execvp(CmdList.front(),ParamList.data()))
+ {
+ std::cerr << "error in execvp: " << strerror(errno) << std::endl;
return errno;
+ }
}
subCount++;
cout <<" PID:"<<iChildPID<<" Count:"<<subCount<< endl;
CmdList.erase(CmdList.begin());
}
+ for( int it = 0; it < Pipes.size(); ++it )
+ {
+ close( close(Pipes[it][0]) );
+ close( close(Pipes[it][1]) );
+ }
int status=0;
cout <<"Waiting for "<<subCount<< endl;
int pid ;
[/сcode]

На самом деле, я бы поправил алгоритм, потому что хранить массив файловых дескрипторов, который передается в ребенка, не очень надежное решение. Например, можно создавать pipe непосредственно перед форком и передавать наследнику только два нужных файловых дескриптора от его пайпов. Наследник для них сделает dup2 и close, а родитель сразу после форка сделает close ненужным концам пайпов. Таким образом не будет создаваться мусора из ненужных файловых дескрипторов, которые еще и нужно закрывать, но в разных местах по разному, чтобы не закрыть чего нужного.
Отредактировано 13.03.2017 21:12 Ssd13 . Предыдущая версия . Еще …
Отредактировано 13.03.2017 21:08 Ssd13 . Предыдущая версия .
Отредактировано 13.03.2017 21:06 Ssd13 . Предыдущая версия .
Re[2]: Нужна консультация fork, pipe, execvp
От: Saddam Россия http://saddam.narod.ru
Дата: 13.03.17 21:35
Оценка:
Здравствуйте, Masterspline, Вы писали:

M>У тебя в массиве Pipes остаются файловые дескрипторы в открытом состоянии (причем как в детях, кроме тех fd, которые заменяются на stdin/out, так и в мастере, прием в нем все fd остаются открытыми), а их нужно закрыть. Иначе программа, читающая из канала не знает когда ей закончить, т.к. в каком-то процессе есть еще открытый файловый дескриптор от пишущего конца канала, хотя процесс, который писал уже завершился.

M>Т.е. происходит следующее (для "who | sort | uniq -c" ):
M>1. создаются дескрипторы для pipe в мастере, затем три ребенка (в которых тоже есть эти дескрипторы).
M>2. первый ребенок меняет и закрывает дескриторы Pipes[0], но оставляет открытыми Pipes[1], затем exec, который пишет и успешно заканчивает работу
M>3. второй ребенок меняет Pipes[1], но сохраняет Pipes[0] и читает что надо, но так как есть еще незакрытые копии файловых дескрипторов для нулевого pipe (в мастере и третьем ребенке), то его записывающий конец не закрыт и sort продолжает пытаться читать. Нужно закрыть все пишущие концы канала в мастере и других детях, чтобы при выходе "who" и закрытии им своего пишущего конца sort на читающем конце считал все, что есть и завершил чтение, т.к. данных больше нет, пишущий конец закрыт.
Очень похоже, но не выходит каменный цветок... Я по-всякому пробовал закрывать дескрипторы....
Я так уже пробовал. Результат ниже (до строки PID... — валит в stderr):
uniq: ошибка чтения '-'
sort: операция stat завершилась неудачно: -: Неправильный дескриптор файла
sort: операция stat завершилась неудачно: -: Неправильный дескриптор файла
who: ошибка записи: Обрыв канала
 PID:2170 Count:1
 PID:2171 Count:2
 PID:2172 Count:3
 PID:2173 Count:4
Waiting for 4
Waiting for 3
PID: 2172 terminated 
Waiting for 2
PID: 2173 terminated 
Waiting for 1
PID: 2171 terminated 
Master is finished!

Дескрипторы куда-то пролюбливаются....
M>Вот мой пропатченный вариант:
M>На самом деле, я бы поправил алгоритм, потому что хранить массив файловых дескрипторов, который передается в ребенка, не очень надежное решение. Например, можно создавать pipe непосредственно перед форком и передавать наследнику только два нужных файловых дескриптора от его пайпов. Наследник для них сделает dup2 и close, а родитель сразу после форка сделает close ненужным концам пайпов. Таким образом не будет создаваться мусора из ненужных файловых дескрипторов, которые еще и нужно закрывать, но в разных местах по разному, чтобы не закрыть чего нужного.
Тоже думал над этим. Пожалуй, завтра утром так и попробую сделать (красивее код получиться должен).
- Вы знаете — жаль, просто по-человечески жаль Памелу Андерсон, которая никогда не сможет сыграть на баяне...
Re[3]: Нужна консультация fork, pipe, execvp
От: Masterspline  
Дата: 13.03.17 23:29
Оценка: 3 (1) +1
Я таки, запутался в массиве дескрипторов Pipes (потому и считаю, что это сложная архитектура и нужно в мастере создавать pipe и передавать наследнику только нужную ему пару дескрипторов).
В предыдущем варианте я закрывал не все дескрипторы, а кроме того, в результате неправильной копипасты, закрывал не то, что нужно (делал close( close(...) ). Исправил.

  Еще раз исправленный код
#include <iostream>
#include <fstream>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <vector>
#include <array>
//#include <algorithm>
//#include <functional>
//#include <cctype>
//#include <locale>
#include <string.h>
#include <sys/wait.h>

using namespace std;

void parse(char *s, char delim, std::vector<char *> &CmdList)
{
    unsigned int l=strlen(s);
    unsigned int i=0;
    CmdList.push_back(s);
    //while (s[strlen(s)-1]==' ') s[strlen(s)-1]=0;
    for (i=0;i<l;i++)
    {
        if (s[i]==delim)
        {
            s[i]=0;
            i++;
            while (s[i]==' ') {s[i]=0;i++;}
            if (strlen(&s[i])) CmdList.push_back(&s[i]);
            while (s[strlen(&s[i])-1]==' ') s[strlen(&s[i])-1]=0;
        }
    }
}
int main() {
    std::filebuf fb;
    fb.open ("./Pipe.log",std::ios::out);
    std::ostream os(&fb);
    std::vector<char *> CmdList;
    char cmdLine[1024];
    int iChildPID=0, subCount=0;
    //cin>>cmdLine;
    strcpy(cmdLine,"who | sort | uniq -c | sort -nk1");
    //strcpy(cmdLine,"who | sort -nk1");
    parse(cmdLine,'|',CmdList);
    std::vector<int *> Pipes;
    for (unsigned int i=0;i<CmdList.size()-1;i++)
    {
        int *Pipe=new int[2];
        Pipes.push_back(Pipe);
        if ( pipe(Pipes[i]) < 0 )
        {
            cout << "Pipe error" << endl;
            return errno;
        }
        os << "Pipe" << i <<": " << Pipes[i][0]<<", "<<Pipes[i][1]<<endl;
    }
    int fd = 0;
    while (!CmdList.empty())
    {
        std::vector<char *> ParamList;
        parse(CmdList.front(),' ',ParamList);
        ParamList.push_back(NULL);
        if (!(iChildPID=fork()))
        {
            if (CmdList.size()>1)
            {
                dup2(Pipes[subCount][1],1);//O_CLOEXEC
                close(Pipes[subCount][0]);
                Pipes[subCount][1]=1;
                os<<getpid()<<" Pipe(>)"<<subCount<<": "<< Pipes[subCount][0]<<", "<<Pipes[subCount][1]<<endl;
            }
            else
            {
                fd = open("./result.out",   O_CREAT | O_RDWR );
                dup2(fd,1);
                os<<getpid()<<" File(>)\n";
            }
            if (subCount)
            {
                dup2(Pipes[subCount-1][0],0);
                Pipes[subCount-1][0]=0;
                close(Pipes[subCount-1][1]);
                os<<getpid()<<" Pipe(<)"<<subCount-1<<": "<< Pipes[subCount-1][0]<<", "<<Pipes[subCount-1][1]<<endl;
            }
            for( int it = 0; it < Pipes.size(); ++it )
            {
                if( (it == subCount) || (it == subCount-1) )
                    continue;
                close(Pipes[it][0]);
                close(Pipes[it][1]);
            }
            if (-1==execvp(CmdList.front(),ParamList.data()))
            {
                std::cerr << "error in execvp: " << strerror(errno) << std::endl;
                return errno;
            }
        }
        subCount++;
        cout <<" PID:"<<iChildPID<<" Count:"<<subCount<< endl;
        CmdList.erase(CmdList.begin());
    }
    for( int it = 0; it < Pipes.size(); ++it )
    {
        close(Pipes[it][0]);
        close(Pipes[it][1]);
    }
    int status=0;
    cout <<"Waiting for "<<subCount<< endl;
    int pid ;
    for (int i=1;i<subCount;i++)
    {
        cout <<"Waiting for "<<subCount-i<< endl;
        pid=wait(&status);
        cout <<"PID: "<<pid<<" terminated \n";
    }
    close(fd);
    cout <<"Master is finished!"<< endl; // prints !!!Hello World!!!
    fb.close();
    return 0;
}
Re: Нужна консультация fork, pipe, execvp
От: Masterspline  
Дата: 14.03.17 04:39
Оценка:
Кстати, вот это тебе может быть полезно:

Курс на степике про сетевое программирование в Linux
Re[2]: Нужна консультация fork, pipe, execvp
От: Saddam Россия http://saddam.narod.ru
Дата: 14.03.17 09:02
Оценка:
Здравствуйте, Masterspline, Вы писали:

M>Кстати, вот это тебе может быть полезно:


M>Курс на степике про сетевое программирование в Linux


Это один из тестов курса
- Вы знаете — жаль, просто по-человечески жаль Памелу Андерсон, которая никогда не сможет сыграть на баяне...
Re[2]: Нужна консультация fork, pipe, execvp
От: Saddam Россия http://saddam.narod.ru
Дата: 14.03.17 10:37
Оценка:
Здравствуйте, Masterspline, Вы писали:

M>Кстати, вот это тебе может быть полезно:


M>Курс на степике про сетевое программирование в Linux

Огромное спасибо за подсказки!
Работающий результат:
#include <iostream>
#include <fstream>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <vector>
#include <string.h>
#include <sys/wait.h>

using namespace std;

void parse(char *s, char delim, std::vector<char *> &CmdList)
{
    unsigned int l=strlen(s);
    unsigned int i=0;
    CmdList.push_back(s);
    for (i=0;i<l;i++)
    {
        if (s[i]==delim)
        {
            s[i]=0;
            i++;
            while (s[i]==' ') {s[i]=0;i++;}
            if (strlen(&s[i])) CmdList.push_back(&s[i]);
            while (s[strlen(&s[i])-1]==' ') s[strlen(&s[i])-1]=0;
        }
    }
}
int main() {
    std::filebuf fb;
    fb.open ("./Pipe.log",std::ios::out);
    std::ostream os(&fb);
    std::vector<char *> CmdList;
    char cmdLine[1024];
    int iChildPID=0, subCount=0;
    //cin>>cmdLine;
    strcpy(cmdLine,"who | sort | uniq -c | sort -nk1");
    parse(cmdLine,'|',CmdList);
    int fd = 0;
    int OutPipe[2]={0,0},inFD=STDIN_FILENO;
    while (!CmdList.empty())
    {
        std::vector<char *> ParamList;
        parse(CmdList.front(),' ',ParamList);
        ParamList.push_back(NULL);
        if ( pipe(OutPipe) < 0 )
        {
            cerr << "Pipe error" << strerror(errno) << endl;
            return errno;
        }
        if (!(iChildPID=fork()))
        {
             close(OutPipe[0]);
             if (dup2(inFD, STDIN_FILENO) == -1) /*read from in_fd */
             {
                 cerr << "child STDIN dup2 error" << strerror(errno) << endl;
                 return errno;
             }
             if (dup2(OutPipe[1], STDOUT_FILENO) == -1)   /*write to fd[1]*/
             {
                 cerr << "child STDOUT dup2 error" << strerror(errno) << endl;
                 return errno;
             }
             else if (close(OutPipe[1]) == -1)
                {
                     cerr << "child CloseFD error" << strerror(errno) << endl;
                     return errno;
                }
            if (CmdList.size()==1)
            {
                fd = open("/home/saddam/result.out",   O_CREAT | O_RDWR );
                dup2(fd,1);
            }
            if (-1==execvp(CmdList.front(),ParamList.data()))
            {
                cerr << "error in execvp: " << strerror(errno) << endl;
                return errno;
            }
        }
        close(OutPipe[1]);   /* parent executes the rest of commands */
        close(inFD);
        inFD=OutPipe[0];
        subCount++;
        cout <<" PID:"<<iChildPID<<" Count:"<<subCount<< endl;
        CmdList.erase(CmdList.begin());
    }
    int status=0;
    int pid ;
    for (int i=0;i<subCount;i++)
    {
        cout <<"Waiting for "<<subCount-i<< endl;
        pid=wait(&status);
        cout <<"PID: "<<pid<<" terminated \n";
    }
    close(fd);
    cout <<"Master is finished!"<< endl; // prints !!!Hello World!!!
    fb.close();
    return 0;
}
- Вы знаете — жаль, просто по-человечески жаль Памелу Андерсон, которая никогда не сможет сыграть на баяне...
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.