2015-09-29 4 views
0

У меня возникли проблемы с реализацией моей трубы. Он считывает команды терминала Unix из текстового файла для таких команд, как «ls | wc», где он открывает канал, так что вывод ls может использоваться для wc.Реализация трубы в C++

Я реализовал его для разбора имен программ («ls», «wc») и сохранил их в двух отдельных массивах (аргументы и аргументы2), разыграл дочерний процесс, а затем у этого дочернего вилка был еще один дочерний процесс, затем второй дочерний процесс вызывает команду execvp() и передает первую исполняемую программу.

Выход из («ls») записывается в трубу путем изменения стандартного выхода. Первый дочерний процесс, а затем execvp() - другой процесс («wc») и считывает из канала, изменяя стандартный ввод.

Однако wc петли бесконечно и, кажется, не подсчитывают количество слов из ls. Ls выполняется в каталоге, где есть слова, которые нужно пересчитать.

Любые советы? Большое вам спасибо и извините за длинное объяснение.

Вот еще один пример: он вилки, создает трубу и реализует «ls» и записывает свой вывод в трубу, возвращается к родительскому и считывает из канала вывод «ls». Кажется, он все время читает или не работает правильно.

// 
// main.cpp 
// Pipe_Test 
// 
// Created by Dillon Sheffield on 9/28/15. 
// Copyright © 2015 Dillon Sheffield. All rights reserved. 
// 

#include <iostream> 
using namespace std; 

int main() 
{ 
    char* arguments[2]; 
    char* programArguments[1]; 
    int fd[2]; 

    arguments[0] = new char[2]; 
    arguments[1] = new char[2]; 
    programArguments[0] = new char[1]; 
    programArguments[0][0] = '\0'; 
    string ls = "ls"; 
    string wc = "wc"; 
    for (int i = 0; i < 1; i++) { 
     arguments[0] = &ls.at(i); 
     arguments[1] = &wc.at(i); 
    } 

    pid_t pid = fork(); 
    pipe(fd); 

    if (pid < 0) { 
     perror("Failed.\n"); 
    } else if (pid == 0) { 
     dup2(fd[1], STDOUT_FILENO); 

     execvp(arguments[0], programArguments); 
    } 

    wait(NULL); 

    dup2(fd[0], STDIN_FILENO); 
    execvp(arguments[1], programArguments); 

    close(0); 
    close(1); 

    return 0; 
} 

Вот мой исходный код:

// 
// main.cpp 
// homework2 
// 
// Created by Dillon Sheffield on 9/19/15. 
// Copyright © 2015 Dillon Sheffield. All rights reserved. 
// 

#include <iostream> 
#include <fstream> 
#include <stdio.h> 
#include <sys/types.h> 
#include <unistd.h> 
using namespace std; 

// Global Variable(s) 
const short inputLineSize = 10; // Size of programName, arguments, and argument name. 
char *arguments[inputLineSize]; 
char *arguments2[inputLineSize]; 
ifstream inputFile; 
char* input; 

void readLine() 
{ 
    // Create new char array(s) 
    input = new char[inputLineSize]; 

    // Initialize the char array(s) 
    for (int i = 0; i < inputLineSize; i++) 
    { 
     input[i] = '\0'; 
    } 

    // Read a line and skip tabs, spaces, and new line characters 
    for (int i = 0; !inputFile.eof() && inputFile.peek() != '\n'; i++) 
    { 
     while (inputFile.peek() == '\n' || inputFile.peek() == '\t' || inputFile.peek() == ' ') inputFile.get(); 
     inputFile.get(input[i]); 
    } 

    // If the file is multi-spaced, keep reading new line char(s) to clear them 
    while (inputFile.peek() == '\n') inputFile.get(); 
} 

void parseTokens() 
{ 
    //----------Parse the read line into tokens--------------------------------------------// 

    // Get the program name 
    for (int i = 0; i < inputLineSize; i++) 
    { 
     arguments[i] = new char[inputLineSize]; 
     for (int j = 0; j < inputLineSize; j++) 
      arguments[i][j] = '\0'; 
    } 

    int i = 0; 
    int j = 0; 
    while (input[i] != '\0' && input[i] != '-' && input[i] != '|') 
    { 
     arguments[j][i] = input[i]; 
     i++; 
    } 

    // Tokenize arguments if supplied 
    j++; 
    int k; 
    while (input[i] == '-') 
    { 
     k = 0; 
     arguments[j][k] = input[i]; 
     i++; 
     k++; 

     while (input[i] != '-' && input[i] != '\0') 
     { 
      arguments[j][k] = input[i]; 
      i++; 
      k++; 
     } 
     j++; 
    } 

    // Delete unused arguments 
    while (j < inputLineSize) 
    { 
     delete arguments[j]; 
     arguments[j] = NULL; 
     j++; 
    } 

    // Check if the pipe command '|' is supplied 
    if (input[i] == '|') 
    { 
     i++; 

     // Get the other program name 
     for (int x = 0; x < inputLineSize; x++) 
     { 
      arguments2[x] = new char[inputLineSize]; 
      for (int y = 0; y < inputLineSize; y++) 
       arguments2[x][y] = '\0'; 
     } 

     int x = 0; 
     int j = 0; 
     while (input[i] != '\0' && input[i] != '-' && input[i] != '|') 
     { 
      arguments2[j][x] = input[i]; 
      i++; 
      x++; 
     } 

     // Tokenize arguments if supplied 
     j++; 
     int k; 
     while (input[i] == '-') 
     { 
      k = 0; 
      arguments2[j][k] = input[i]; 
      i++; 
      k++; 

      while (input[i] != '-' && input[i] != '\0') 
      { 
       arguments2[j][k] = input[i]; 
       i++; 
       k++; 
      } 
      j++; 
     } 

     // Delete unused arguments 
     while (j < inputLineSize) 
     { 
      delete arguments2[j]; 
      arguments2[j] = NULL; 
      j++; 
     } 
    } 
} 

int main() 
{ 
    // Variable(s) 
    pid_t pid; 
    pid_t pid2; 
    int fd[2]; 

//--Open the file named "input"-------------------------------------------------------// 

    inputFile.open("input", ios::in); 

    // Check if opening the file was successful 
    if (inputFile.is_open()) 
    { 
     // Read until the file has reached the end 
     while (!inputFile.eof()) 
     { 
      // Read a line and parse tokens 
      readLine(); 
      parseTokens(); 

//----------Now create a new process with parsed Program Name and Arguments-----------// 

      // Create a pipe 
      pipe(fd); 

      // Fork 
      pid = fork(); 
      if (pid < 0) 
      { 
       perror("Fork failed.\n"); 
       return -2; 
      } 
      else if (pid == 0) 
      { 
       // Fork again 
       pid2 = fork(); 

       if (pid2 < 0) 
       { 
        perror("Fork failed.\n"); 
        return -2; 
       } 
       else if (pid2 == 0) 
       { 
        // Change standard output 
        if (dup2(fd[1], STDOUT_FILENO) != STDOUT_FILENO) perror("dup2 error to stdout.\n"); 

        // Execute the given program 
        execvp(arguments[0], arguments); 
       } 


       // Change the standard input to the pipe 
       if (dup2(fd[0], STDIN_FILENO) != STDIN_FILENO) perror("dup2 error to stdin.\n"); 

       int returnValue = execvp(arguments2[0], arguments2); 
       if (returnValue == -1) perror("Error has occurred.\n"); 

       // Close the pipe and exit 
       close(fd[0]); 
       close(fd[1]); 
       exit(0); 
      } 

      // Wait for the child so it doesn't become a Zombie 
      wait(NULL); 


//----------Clean up-----------------------------------------------------------------// 
      delete input; 
      input = NULL; 
      int i = 0; 
      while (arguments[i] != NULL) 
      { 
       delete arguments[i]; 
       arguments[i] = NULL; 
       i++; 
      } 
      i = 0; 
     } 
    } 
    else perror("Cannot open file.\n"); 

    inputFile.close(); 
    return 0; 
} 
+2

Кажется, что вы пытаетесь выполнить сразу две сложные вещи: чтение/разбор команд unix и выполнение их с помощью вилок и труб. * Разделите * эти две вещи и испытайте их изолированно; по крайней мере, это приблизит вас к [минимальному полному примеру] (http://stackoverflow.com/help/mcve). – Beta

ответ

0

Сначала выполните операцию pipe(), то вы выполняете fork() и дочерний процесс, с некоторой дополнительной работой, выполняет ваши команды.

Проблема заключается в том, что дескрипторы файла pipe() d, оба из них, остаются открытыми в исходном родительском процессе. Как на стороне считывания трубы, так и, что более важно, на стороне записи трубы. Эти дескрипторы файлов, по всей видимости, корректно настроены для ваших дочерних процессов, но поскольку дескрипторы файлов также остаются открытыми в родительском процессе, труба никогда не закрывается, даже после того, как процесс, который записывает на сторону записи в трубе, завершается ,

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

Что вам нужно сделать, так это то, что после того, как вилка в родительском процессе закроет как прочитанную, так и записывающую сторону трубы. Как только начальный процесс распадается, родительскому процессу не нужен канал, и его дескрипторы открытого файла мешают.

+0

Спасибо, Сэм. Кажется, я не могу заставить его работать. Где я должен точно добавить команды close (fd [0]) и close (fd [1])? Наверное, я немного смущен этим. – CheerfulBiscuit

+0

В родительском процессе, как я объяснил. –

+0

Мой код закрывает концы труб в родительском процессе? – CheerfulBiscuit

Смежные вопросы