C++ в Linux: пайпы

Модератор: Модераторы разделов

Аватара пользователя
Xaktyc
Сообщения: 604
ОС: Gentoo 2008.0, WinXP

C++ в Linux: пайпы

Сообщение Xaktyc »

Имеется задание сделать вычисление формулы по частям - в трех форках.
Первая часть задания - сделать связь через файлы и переменные выполнить.
Затруднения с третьей задачей - связь через пайпы.
Где можно почитать что-нибудь понятное для новичка в C про пайпы?
Ну или буду очень благодарен за небольшой пример как можно из дочернего в главный процесс через пайп передать значение переменной.
Спасибо сказали:
Аватара пользователя
eddy
Сообщения: 3321
Статус: Красный глаз тролля
ОС: ArchLinux

Re: C++ в Linux: пайпы

Сообщение eddy »

У меня на столе лежит хорошая книжка: Уильям Стивенс "UNIX. Взаимодействие процессов" :)
Там и про shm, и про потоки/нити FIFO/LIFO и пр. Т.к. вам нужно ожидать завершения выполнения дочерних процессов (или нитей), то придется использовать, например, семафоры, либо запускать дочерний поток и ждать его завершения. А значение переменной не обязательно передавать через каналы - можно и разделяемую память использовать.
RTFM
-------
KOI8-R - патриотичная кодировка Изображение
Спасибо сказали:
Аватара пользователя
begin2009
Сообщения: 349
Статус: Ламер со стажем
ОС: без глюков

Re: C++ в Linux: пайпы

Сообщение begin2009 »

Посмотрите сюды
Все подробно, с кучей примеров.
Пессимист видит темный туннель, оптимист видит свет в конце туннеля, реалист видит свет, туннель и поезд.
И только машинист видит этих трех идиотов, сидящих на рельсах.
Спасибо сказали:
Аватара пользователя
Xaktyc
Сообщения: 604
ОС: Gentoo 2008.0, WinXP

Re: C++ в Linux: пайпы

Сообщение Xaktyc »

eddy писал(а):
03.12.2009 14:24
Т.к. вам нужно ожидать завершения выполнения дочерних процессов (или нитей), то придется использовать, например, семафоры, либо запускать дочерний поток и ждать его завершения.

Там ожидается завершения. Все что надо уже сделано. Надо то же самое тока под пайпы переделать...
begin2009 писал(а):
03.12.2009 18:41
Посмотрите сюды
Все подробно, с кучей примеров.

Спасибо. Завтра попытаюсь осилить.
Спасибо сказали:
NickLion
Сообщения: 3408
Статус: аватар-невидимка
ОС: openSUSE Tumbleweed x86_64

Re: C++ в Linux: пайпы

Сообщение NickLion »

Ой, раз задали вопрос про пайпы... Давно висит задачка, всё никак не вернусь к ней. В общем суть такая: имеется N процессов, каждый из них связан через пайпы с нулевым :). В определенный момент времени двум процессам надо организовать общение, но не через 0-й (чтобы не нагружать). Можно ли обойтись безымянными пайпами? Или придется всё же делать FIFO (aka именованные пайпы)?
Спасибо сказали:
Slimy
Сообщения: 1689
ОС: openSuSE 11.2 GM (GеMор едишн)

Re: C++ в Linux: пайпы

Сообщение Slimy »

А что есть pid=0? просто там в примерах на основании этого направление передачи через пайп выбирается.
Если уже ничего не помогает - прочти инструкцию.
sysinstall - гадость :)
ASUS A6q00Vm Pentium-M 1.7 GHz, 2Gb RAM, 160Gb HDD,
GeForce Go 7300 64Mb video
Спасибо сказали:
Аватара пользователя
begin2009
Сообщения: 349
Статус: Ламер со стажем
ОС: без глюков

Re: C++ в Linux: пайпы

Сообщение begin2009 »

Slimy писал(а):
04.12.2009 17:08
А что есть pid=0? просто там в примерах на основании этого направление передачи через пайп выбирается.

PID - положительное целое число, однозначно идентифицирующее процесс в течение времени его жизни. Процессов с PID==0 не будет в принципе. Для текущего контроля состояния процессов в системе используется команда ps. Заданная без параметров, она выводит список PID процессов данного пользователя, с опцией -A - список всех процессов в системе. Запустите в терминале. Все PID - многозначные числа. В программе PID можно получить функцией getpid() с прототипом:
#include <sys/types.h>
#include <unistd.h>
pid_t getpid(void);
(Тип данных pid_t является синонимом для одного из целочисленных типов языка C).
В примерах если PID нулевой, то это признак что такого процесса нет.
Пессимист видит темный туннель, оптимист видит свет в конце туннеля, реалист видит свет, туннель и поезд.
И только машинист видит этих трех идиотов, сидящих на рельсах.
Спасибо сказали:
Slimy
Сообщения: 1689
ОС: openSuSE 11.2 GM (GеMор едишн)

Re: C++ в Linux: пайпы

Сообщение Slimy »

begin2009 писал(а):
04.12.2009 18:35
Slimy писал(а):
04.12.2009 17:08
А что есть pid=0? просто там в примерах на основании этого направление передачи через пайп выбирается.

PID - положительное целое число, однозначно идентифицирующее процесс в течение времени его жизни. Процессов с PID==0 не будет в принципе. Для текущего контроля состояния процессов в системе используется команда ps. Заданная без параметров, она выводит список PID процессов данного пользователя, с опцией -A - список всех процессов в системе. Запустите в терминале. Все PID - многозначные числа. В программе PID можно получить функцией getpid() с прототипом:
#include <sys/types.h>
#include <unistd.h>
pid_t getpid(void);
(Тип данных pid_t является синонимом для одного из целочисленных типов языка C).
В примерах если PID нулевой, то это признак что такого процесса нет.


спасибо за подробности про pid я в курсе был просто предполагал что 0 какой то особый смысл имеет просто в примере

Код: Выделить всё

           if((childpid = fork()) == -1)
           {
                   perror("fork");
                   exit(1);
           }
           if(childpid == 0)
           {
                   /* Потомок закрывает вход */
                   close(fd[0]);
           }
           else
           {
                   /* Родитель закрывает выход */
                   close(fd[1]);
           }
вот такое творится как тут быть?
Если уже ничего не помогает - прочти инструкцию.
sysinstall - гадость :)
ASUS A6q00Vm Pentium-M 1.7 GHz, 2Gb RAM, 160Gb HDD,
GeForce Go 7300 64Mb video
Спасибо сказали:
pcodr
Сообщения: 283
ОС: Debian

Re: C++ в Linux: пайпы

Сообщение pcodr »

В потомке fork возвращает 0, в родителе pid потомка, при неудаче -1 в родителе.
man fork
remote system type is unix
Спасибо сказали:
Аватара пользователя
Xaktyc
Сообщения: 604
ОС: Gentoo 2008.0, WinXP

Re: C++ в Linux: пайпы

Сообщение Xaktyc »

Насколько я помню, если ты делаешь что-то типа
int pid=fork();
тогда pid=номеру форка. Если правильно составить условие - тогда если 0 - выполнение ведется в родителе, если нет - в форке.
Спасибо сказали:
Аватара пользователя
begin2009
Сообщения: 349
Статус: Ламер со стажем
ОС: без глюков

Re: C++ в Linux: пайпы

Сообщение begin2009 »

Подправлюсь, действительно у работающего процесса из консоли pid равный нулю мы не найдем. А вот если форком запустим другой процесс, то да. У порожденного процесса по сравнению с процессом-предком изменяются значения следующих параметров: идентификатор процесса - PID; идентификатор родительского процесса - PPID.

Для иллюстрации сказанного рассмотрим программу:

Код: Выделить всё

/* Программа fork.с - пример создания нового процесса
   с одинаковой работой процессов предка и потомка */

#include <sys/types.h>
#include <unistd.h>
#include <stdio.h>

int main()
{
    pid_t pid, ppid;
    int a = 0;

    fork();

    /* При успешном создании нового процесса
       с этого места псевдопараллельно
       начинают работать два процесса: старый
       и новый */
    /* Перед выполнением следующего выражения
       значение переменной a в обоих процессах
       равно 0 */

    ++a;

    /* Узнаем идентификаторы текущего и роди-
       тельского процесса (в каждом из процессов !!!) */

    pid = getpid();
    ppid = getppid();

    /* Печатаем значения PID, PPID и вычислен-
       ное значение переменной a (в каждом из процессов !!!) */

    printf("My pid = %d, my ppid = %d, result = %d\n",
            (int)pid, (int)ppid, a);

    getchar();
    return 0;
}

Системный вызов fork() возвращает в процессы предок и потомок различные значения. При успешном создании нового процесса в процесс-предок возвращается
положительное значение, равное идентификатору процесса-потомка. В процесс-потомок же возвращается значение 0. Если по какой-либо причине создать новый
процесс не удалось, то системный вызов вернет в инициировавший его процесс значение -1.
PS Скопировал из лекций по операционным системам у сына. Копирайт на текст у его препода.
Пессимист видит темный туннель, оптимист видит свет в конце туннеля, реалист видит свет, туннель и поезд.
И только машинист видит этих трех идиотов, сидящих на рельсах.
Спасибо сказали:
Slimy
Сообщения: 1689
ОС: openSuSE 11.2 GM (GеMор едишн)

Re: C++ в Linux: пайпы

Сообщение Slimy »

begin2009 писал(а):
05.12.2009 12:43
Подправлюсь, действительно у работающего процесса из консоли pid равный нулю мы не найдем. А вот если форком запустим другой процесс, то да. У порожденного процесса по сравнению с процессом-предком изменяются значения следующих параметров: идентификатор процесса - PID; идентификатор родительского процесса - PPID.

Для иллюстрации сказанного рассмотрим программу:

Код: Выделить всё

/* Программа fork.с - пример создания нового процесса
    с одинаковой работой процессов предка и потомка */

 #include <sys/types.h>
 #include <unistd.h>
 #include <stdio.h>

 int main()
 {
     pid_t pid, ppid;
     int a = 0;

     fork();

     /* При успешном создании нового процесса
        с этого места псевдопараллельно
        начинают работать два процесса: старый
        и новый */
     /* Перед выполнением следующего выражения
        значение переменной a в обоих процессах
        равно 0 */

     ++a;

     /* Узнаем идентификаторы текущего и роди-
        тельского процесса (в каждом из процессов !!!) */

     pid = getpid();
     ppid = getppid();

     /* Печатаем значения PID, PPID и вычислен-
        ное значение переменной a (в каждом из процессов !!!) */

     printf("My pid = %d, my ppid = %d, result = %d\n",
             (int)pid, (int)ppid, a);

     getchar();
     return 0;
 }

Системный вызов fork() возвращает в процессы предок и потомок различные значения. При успешном создании нового процесса в процесс-предок возвращается
положительное значение, равное идентификатору процесса-потомка. В процесс-потомок же возвращается значение 0. Если по какой-либо причине создать новый
процесс не удалось, то системный вызов вернет в инициировавший его процесс значение -1.
PS Скопировал из лекций по операционным системам у сына. Копирайт на текст у его препода.

Да спс теперь все понятно. ppid () это parent pid? Причем вроде как припоминаю в универе тоже подобный код видел. А вот в примерах двльше увидел.
char *strings[MAXSTRS] = {"echo", "bravo", "alpha", "charlie", "delta"};
к теме не относится но стало интересно как это в массив типа char стринги влезают?
Если уже ничего не помогает - прочти инструкцию.
sysinstall - гадость :)
ASUS A6q00Vm Pentium-M 1.7 GHz, 2Gb RAM, 160Gb HDD,
GeForce Go 7300 64Mb video
Спасибо сказали:
Аватара пользователя
Xaktyc
Сообщения: 604
ОС: Gentoo 2008.0, WinXP

Re: C++ в Linux: пайпы

Сообщение Xaktyc »

Slimy писал(а):
05.12.2009 13:06
ppid () это parent pid?

Да.
Slimy писал(а):
05.12.2009 13:06
к теме не относится но стало интересно как это в массив типа char стринги влезают?

Ну тут же вроде указатель на область. Если я не ошибаюсь, если писать в двойных кавычках - пишется некоторое количество символов. Если в одинарных - один символ.

ЗЫ. Вопрос: тут кто-нить код по топику привести может вообще?:)
Спасибо сказали:
pcodr
Сообщения: 283
ОС: Debian

Re: C++ в Linux: пайпы

Сообщение pcodr »

Написал для пробы. Сам на си не пишу ибо сложный, так что за качество не ручаюсь.

Тут создаётся потомок, между родителем и потомком канал. Потомок вычисляет 10 больших простых чисел самым тормозным методом - методом перебора и по мере вычисления пишет их в канал, уведомляя об этом родителя с пмощью сигнала таймера. Родитель в свою очередь получив сигнал таймера читает из канала прешедшее число. Между тем родитель занят своими вычислениями, в данном случаи просто спит и печатает сообщения.

Код: Выделить всё

#include<sys/types.h>
#include<sys/wait.h>
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<signal.h>
#include<math.h>

int pipes[2];

void sig_chld(int sig)
{ // sigchld handler
    int status;

    // clean zombies
    waitpid(-1, &status, WNOHANG);
    puts("Child exit successfully");
}

void sig_alrm(int sig)
{ // sigalrm handler
    int len;
    char *buf;

    buf = malloc(10);
    len = read(pipes[0], buf, 9);

    printf("received prime from child: %s\n", buf);
    free(buf);
}

int rank_num(long long num)
{
    int i = 1;

    while(num % (long long)pow(10, i) != num)
    {
        i++;
    }

    return i;
}

int main()
{
    pid_t child;
    int i;
    struct sigaction act;

    // install sigchld handler
    act.sa_handler = sig_chld;

    if(sigaction(SIGCHLD, &act, NULL) == -1)
    {
        perror("sigaction failed");
        return(1);
    }

    // install sigalrm handler
    act.sa_handler = sig_alrm;

    if(sigaction(SIGALRM, &act, NULL) == -1)
    {
        perror("sigaction failed");
        return(1);
    }

    // create pipe
    if(pipe(pipes) == -1)
    {
        perror("failed to create pipe");
        return(1);
    }

    // fork
    if((child = fork()) == -1)
    {
        perror("fork failed");
        return(1);
    }

    if(!child)
    { // this is child
        close(pipes[0]); // close unused pipe end: reader

        // try to get next big prime (stupid way)
        long long prime = 160481183;
        int cnt, len;
        char *buf = NULL;
        pid_t parent;

        // get parent pid
        parent = getppid();

        for(cnt=0; cnt<10;)
        { // try to find 10 primes
            prime++;

            for(i=2; i<prime; i++)
            {
                if(prime % i == 0)
                { // this is not prime
                    break;
                }
            }

            if(i == prime)
            { // prime found, send it to parent
                len = rank_num(prime);

                buf = realloc(buf, len+1);
                if(!buf)
                {
                    perror("failed to realloc memory");
                    return(1);
                }

                sprintf(buf, "%d", prime);
                write(pipes[1], buf, len);

                // hay parent, there is a new data in the pipe
                kill(parent, SIGALRM);
                cnt++;
            }
        }

        free(buf);
        close(pipes[1]);
    }
    else
    { // this is parent
        close(pipes[1]); // close unused pipe end: writer

        for(i=0;;i++)
        { // parent do some job
            printf("parent job: %d%\n", i);
            sleep(3);
        }

        close(pipes[0]);
    }

    return 0;
}


gcc -lm filename.c
remote system type is unix
Спасибо сказали:
Аватара пользователя
RasenHerz
Сообщения: 1341
ОС: Arch Linux amd64

Re: C++ в Linux: пайпы

Сообщение RasenHerz »

Почему бы не использовать вместо пайпов разделямую память? На мой взгляд, получится довольно аккуратно: создаете структуру со всеми необходимыми данными, заполняете ее, а потом копируете в разделяемую память ( c помощью того же memcpy ) - все.
Спасибо сказали:
Slimy
Сообщения: 1689
ОС: openSuSE 11.2 GM (GеMор едишн)

Re: C++ в Linux: пайпы

Сообщение Slimy »

RasenHerz писал(а):
05.12.2009 22:19
Почему бы не использовать вместо пайпов разделямую память? На мой взгляд, получится довольно аккуратно: создаете структуру со всеми необходимыми данными, заполняете ее, а потом копируете в разделяемую память ( c помощью того же memcpy ) - все.

а может быть вы небольшой примерчик приложите так сказать продемонстрировать преимущество подхода.
Если уже ничего не помогает - прочти инструкцию.
sysinstall - гадость :)
ASUS A6q00Vm Pentium-M 1.7 GHz, 2Gb RAM, 160Gb HDD,
GeForce Go 7300 64Mb video
Спасибо сказали:
Satana666
Сообщения: 4
ОС: В поиске подходящей ОС!

Re: C++ в Linux: пайпы

Сообщение Satana666 »

Разделяемая память не катит, ибо нужно сделать на пайпах! (Учусь с Xaktyc)
Спасибо сказали:
Аватара пользователя
Xaktyc
Сообщения: 604
ОС: Gentoo 2008.0, WinXP

Re: C++ в Linux: пайпы

Сообщение Xaktyc »

Slimy писал(а):
06.12.2009 14:19
Почему бы не использовать вместо пайпов разделямую память?

Если я не ошибаюсь, первый мой вариант был через подобие разделенки :)
Но от нас требуют файлы и пайпы (ну по программе изучения) - файлы я сделал, надо пайпы.
Спасибо сказали:
Satana666
Сообщения: 4
ОС: В поиске подходящей ОС!

Re: C++ в Linux: пайпы

Сообщение Satana666 »

Вот "Быдлокод" который я написал... Помогите исправить!
В пайп вроде пишет но непонятно что. Похоже что главный процесс не дожидается пока форки запишут данные в пайп.

Код: Выделить всё

#include <iostream>
#include <stdlib.h>
#include <unistd.h>

using namespace std;

int main(int argv, char *argc[])
{
int n,k;
int faktN,faktK,pow;
int fd1[2],fd2[2],fd3[2];

n=atoi(argc[1]);
k=atoi(argc[2]);

int  pr1,pr2,pr3;

pr1=fork();
if(pr1==0)
{
    pipe(fd1);
    dup2(fd1[1],1);
    execl("fakt",argc[1]);
close(fd1[1]);
}


pr2=fork();

if (pr2==0)
{
    pipe(fd2);
    dup2(fd2[1],1);
    execl("fakt",argc[2]);
close(fd2[1]);
}

pr3=fork();

if (pr3==0)
{
    pipe (fd3);
    dup2(fd3[1],1);
    execl("pow",argc[1],argc[1],argc[2]);
close(fd3[1]);
}



char readbuffer1[50];
char readbuffer2[50];
char readbuffer3[50];

char bufN,bufK,buf_pow;

bufN=read(fd1[0], readbuffer1,sizeof( readbuffer1));
bufK=read(fd2[0],readbuffer2,sizeof( readbuffer2));
buf_pow=read(fd3[0],readbuffer3,sizeof( readbuffer3));

int rez;

faktN=atoi(bufN);
faktK=atoi(bufK);
pow=atoi(buf_pow);

rez=(faktN-faktK)/pow;

cout<<rez<<endl;


return 0;
}
Спасибо сказали:
Аватара пользователя
Xaktyc
Сообщения: 604
ОС: Gentoo 2008.0, WinXP

Re: C++ в Linux: пайпы

Сообщение Xaktyc »

Нас бы интересовало как грамотно воспользоваться wait или waitpid(), разобраться не получилось пока.
Спасибо сказали:
pcodr
Сообщения: 283
ОС: Debian

Re: C++ в Linux: пайпы

Сообщение pcodr »

Смотрите мой пример, там есть waitpid. Смысл такой: при завершении потомка родителю поступает сигнал SIGCHLD, у родителя должен стоять обработчик этого сигнала, а именно вызываться waitpid, который убирает завершившиеся дочерние процессы из таблицы процессов, дабы они не висели там в виде зомби.
remote system type is unix
Спасибо сказали:
Satana666
Сообщения: 4
ОС: В поиске подходящей ОС!

Re: C++ в Linux: пайпы

Сообщение Satana666 »

Так вот код который у нас имеется после недельного обсуждения проблемы на форумах!

Код: Выделить всё

#include <iostream>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>

using namespace std;

int main(int argv, char *argc[])
{
int n,k;
int faktN,faktK,pow;
int fd1[2],fd2[2],fd3[2];

int  pr1,pr2,pr3;

pipe(fd1);
pr1=fork();
if(pr1==0)
{

close(fd1[0]);
dup2(fd1[1],1);
execl("fakt",argc[1]);
} else
close(fd1[1]);

pipe(fd2);
pr2=fork();
if (pr2==0)
{
    close(fd2[0]);
    dup2(fd2[1],1);
    execl("fakt",argc[2]);

}else
close(fd2[1]);

pipe(fd3);
pr3=fork();
if (pr3==0)
{
    close(fd3[0]);
    dup2(fd3[1],1);
    execl("pow",argc[1],argc[1],argc[2]);
   }else
close(fd3[0]);

char buf1[50];
char buf2[50];
char buf3[50];

read(fd1[0],buf1,sizeof(buf1));
read(fd2[0],buf2,sizeof(buf2));
read(fd3[0],buf3,sizeof(buf3));
cout<<buf1<<"------"<<buf2<<"-------"<<buf3<<endl;

float rez;

faktN=atoi(buf1);
faktK=atoi(buf2);
pow=atoi(buf3);

cout<<faktN<<"||"<<faktK<<"||"<<pow<<endl;

rez=(faktN-faktK)/pow;

cout<<rez<<endl;


return 0;
}


Сейчас в пайпы пишет нормально. Но, возникла следующая проблема! при выводе buf1,buf2,buf3 на экране появляются непонятные кракозябры, если выводить этиже массивы после преобразования из в int, то выводит нули.
Спасибо сказали:
Аватара пользователя
Xaktyc
Сообщения: 604
ОС: Gentoo 2008.0, WinXP

Re: C++ в Linux: пайпы

Сообщение Xaktyc »

Satana666 писал(а):
15.12.2009 10:44
read(fd1[0],buf1,sizeof(buf1));
read(fd2[0],buf2,sizeof(buf2));
read(fd3[0],buf3,sizeof(buf3));

Это ведь еще до того, как мы все поменяли местами и начали закрывать пайпы...
Лучше бы ты попозже код с сервера выложил.
UPD:
Если это новый код, нафига отладочную инфу убрал?
Спасибо сказали:
Satana666
Сообщения: 4
ОС: В поиске подходящей ОС!

Re: C++ в Linux: пайпы

Сообщение Satana666 »

Xaktyc писал(а):
15.12.2009 13:20
Satana666 писал(а):
15.12.2009 10:44
read(fd1[0],buf1,sizeof(buf1));
read(fd2[0],buf2,sizeof(buf2));
read(fd3[0],buf3,sizeof(buf3));

Это ведь еще до того, как мы все поменяли местами и начали закрывать пайпы...
Лучше бы ты попозже код с сервера выложил.
UPD:
Если это новый код, нафига отладочную инфу убрал?


Это новый код! Я его утром писал!
инфу не проблема включить!
Спасибо сказали: