5 / 5 / 0
Регистрация: 10.10.2014
Сообщений: 86
1

Не получается сделать конвейер на пайпах

15.08.2018, 01:00. Показов 1574. Ответов 5

Author24 — интернет-сервис помощи студентам
Здравствуйте.

Изучаю основы программирования под Linux, сейчас вот пробую разобраться с межпроцессорным взаимодействием, а именно - с пайпами. Есть такой код:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
    int pfd[2];
    int hPrevOut;
    for(size_t i = 0; i < vCommands.size(); ++i)
    {
        hPrevOut = pfd[0];
        if(i < vCommands.size() - 1){
            pipe(pfd);
            std::cout << "NEW PIPE" << pfd[0] << "-" << pfd[1] << std::endl;
        }
        if(i > 0)
            std::cout << i << ": STDIN WILL BE " << hPrevOut << std::endl; 
        if(i < vCommands.size() - 1)
            std::cout << i << ": STDOUT WILL BE " << pfd[1] << std::endl;
        
        if(!fork())
        {
            if(i > 0)
            {
                close(STDIN_FILENO);
                dup2(hPrevOut, STDIN_FILENO);
                close(hPrevOut);
            }
            close(STDOUT_FILENO);
            if(i < vCommands.size() - 1)
            {
                
                dup2(pfd[1], STDOUT_FILENO);
                close(pfd[1]);           
            }
            else
            {
                unlink("/home/usr/result");
                int fd = open("/home/usr/result", 
                    O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
                dup2(fd, STDOUT_FILENO);
                //close(fd);
            }
           execvp(vCommands.at(i).sCommand.c_str(),vCommands.at(i).vArgs.data());
        }
    }
Что должен делать: выводить результат набора команд (к примеру who | sort | uniq) в файл result.
Что делает: с одной командой работает, но с несколькими создает пустой файл result, данные между вызовами теряются. Прикрутил вывод, чтобы смотреть как соединяю вводы - выводы пайпами - вроде все как нужно, либо я в принципе неверно понимаю суть работы с пайпами.
Объясните, пожалуйста, что я делаю не так
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
15.08.2018, 01:00
Ответы с готовыми решениями:

Конвейер
Доброго времени суток. Помогите разобраться с &quot;конвейером&quot;. В литературе сказано что при передаче...

Конвейер
Имеется такой код: library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_ARITH.ALL; ...

Скрипт-Конвейер
Приветствую. Нужен скрипт для программы СтелсБот, который поддерживает встраивание VBS скриптов....

Поточный конвейер
Для эффективного использования вычислительных мощностей, в моей программе требуется использовать...

5
Параллельный Кот
1905 / 827 / 350
Регистрация: 25.03.2016
Сообщений: 2,045
15.08.2018, 02:39 2
Вы уверены, что правильно понимаете, как работает системный вызов fork() ?

Если кратко, то fork() создает точную копию родительского процесса, после чего уже два одинаковых (ничем не отличимых) процесса продолжают свою работу со следующей команды после ветвления. Один из способов их отличить - fork() вернет родителю id потомка, а потомок вместо этого получит 0. Здесь пока в вашей программе все правильно.

Далее, что делают ваши процессы?

(1) Родительский процесс, убедившись, что он не потомок, переходит к следующей команде, снова "форкает" себя и т.д. для каждой команды из списка.

(2) Все потомки (!) являются потомками одного и того же родительского процесса! Каждый из них делает какие-то там манипуляции с каналами и потоками ввода/вывода, после чего заменяет свой образ на указанный в команде, не переходя к следующей команде.

Итого: хотели сделать цепочку вызовов, а получили звезду. Кажется, немного не то.

Необходимо каким-то образом заставить потомков не сразу выполнять exec(), а сначала перейти к следующей команде, "форкнуть" себя, а только потом обработать свою команду. А первоначального родителя отучить от вредной привычки плодить свои копии. Надеюсь, натолкнул на мысли, как исправить ошибки. Если не совсем понятно или что-то не получится - пишите, попробую сделать пример программы, некоторый опыт в этой области имеется.
0
5 / 5 / 0
Регистрация: 10.10.2014
Сообщений: 86
15.08.2018, 09:21  [ТС] 3
Цитата Сообщение от valen10 Посмотреть сообщение
Вы уверены, что правильно понимаете, как работает системный вызов fork()
Да, с этим разобрался. И copy on write при назначении пайпов как раз учел.

Цитата Сообщение от valen10 Посмотреть сообщение
Итого: хотели сделать цепочку вызовов, а получили звезду.
А вот тут я проблем и не видел (приложил картинку). Полагал, если в ядре мы подменили дескриптор на пайповский, то даже не страшно если exec выполнится раньше чем будет готов читать следующий процесс - данные буфферизируются и процесс прочитает их когда будет готов. Видимо, я неправильно это понимаю, попробую сейчас переписать это рекурсивно, причем начинать плодить видимо нужно с последней команды, чтобы после exec она ожидала ввода stdin от создаваемой на следующем шаге команды.
Миниатюры
Не получается сделать конвейер на пайпах  
0
5 / 5 / 0
Регистрация: 10.10.2014
Сообщений: 86
15.08.2018, 10:09  [ТС] 4
И рекурсивно тоже не работает. Не понимаю, что я делаю не так
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
struct Command
{
    std::string sCommand;
    std::vector<char*> vArgs;
};
 
void execCommand(const std::vector<Command>& vComm, int iCurrComm, int hOut)
{
    if(iCurrComm >= 0 && !fork())
    {
        close(STDOUT_FILENO);
        dup2(hOut, STDOUT_FILENO); //pfd[1]
        close(hOut);
        if(iCurrComm > 0)
        {
            int pfd[2];
            pipe(pfd);
            
            close(STDIN_FILENO);
            dup2(pfd[0], STDIN_FILENO);
            close(pfd[0]);
 
            execCommand(vComm, iCurrComm - 1, pfd[1]);
        }
        //throw std::runtime_error(std::to_string(iCurrComm) + vComm.at(iCurrComm).sCommand);
        execvp(vComm.at(iCurrComm).sCommand.c_str(),vComm.at(iCurrComm).vArgs.data());   
    }
}
 
int main(int argc, char ** argv)
{
//...
    unlink("/home/usr/result");
    int fd = open("/home/usr/result", O_RDWR | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH |     S_IWOTH);
    execCommand(vCommands, vCommands.size() - 1, fd);
}
0
Evg
Эксперт CАвтор FAQ
21279 / 8301 / 637
Регистрация: 30.03.2009
Сообщений: 22,659
Записей в блоге: 30
15.08.2018, 10:28 5
В твои коды не смотрел.
Можешь попробовать взять за основу https://www.cyberforum.ru/c-li... post973482
0
5 / 5 / 0
Регистрация: 10.10.2014
Сообщений: 86
15.08.2018, 13:14  [ТС] 6
Изучил логи strace - неправильно я дескрипторы закрывал!
Работающее рекурсивное решение (может, кому пригодится):
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
void execCommand(const std::vector<Command>& vComm, int iCurrComm, int hOut)
{
    if(iCurrComm >= 0 && !fork())
    {
        close(STDOUT_FILENO);
        dup2(hOut, STDOUT_FILENO); //pfd[1]
        close(hOut);
        if(iCurrComm > 0)
        {
            int pfd[2];
            pipe(pfd);
            
            close(STDIN_FILENO);
            dup2(pfd[0], STDIN_FILENO);
            close(pfd[0]);
            
 
            execCommand(vComm, iCurrComm - 1, pfd[1]);
            close(pfd[1]);//Вот здесь важный момент!!!
        }
        execvp(vComm.at(iCurrComm).sCommand.c_str(),vComm.at(iCurrComm).vArgs.data());   
    }
}
Сейчас гляну, может и итеративное решение с fork из main на самом деле работало
0
15.08.2018, 13:14
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
15.08.2018, 13:14
Помогаю со студенческими работами здесь

про конвейер
На конвейер .поступают однотипные изделия, изготовленные двумя рабочими. При этом первый поставляет...

Весовой конвейер
mojno li sdelat' na sdaka lentochnii conveyor i izmerit' ves materiala? Ya hochu uznat' rashod...

Стандартный конвейер
Здравствуйте,форумчане) работаю с шейдерами посредство glew.h. С помощью функции:...

Комплектовочный конвейер
Условие: На комплектовочный конвейер сборочного цеха каждые 5 +- 1 минута поступают 5 изделий...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
6
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru