2016-12-13 3 views
-4

Привет всем,C домашнее задание с трубами и вилок

Я совсем потерялась в моей школе домашнее задание, так как они не сказали нам много об этом, и я ничего подобного не делал раньше.

Задача:

В языке C создать программу, которая создает два процесса (вилка функция) и соединяет их через трубу (функция трубы). Первый потомок перенаправляет свой 'stdout в трубу и записывает (пробелы) пары случайных чисел в него (функция rand). Задержка вывода чисел (то есть на 1 секунду).

Первый потомок имеет , чтобы обработать сигнал SIGUSR1 (функция sigaction) и в случае получения такого сигнала он печатает строку «TERMINATED», чтобы это STDERR и заканчивается.

Второй потомок перенаправляет вывод трубы на это STDIN, перенаправляет это стандартный вывод в файл с именем out.txt в текущей директории и выполняет двоичный файл (функция execl) для нахождения наибольшего общего делителя (выход из наших предыдущих задач, когда нам приходилось писать make-файл, который запускает небольшую программу на C, которая определяет, является ли число простым).

Родительский процесс ждет 5 секунд и затем отправляет SIGUSR1 в первый процесс (генератор чисел). Это должно привести к правильному завершению обоих процессов. Он ожидает завершения субпроцессов (функция ожидания) и завершает себя.

Фактически вы реализуете что-то вроде этого: while:; do echo $ RANDOM $ RANDOM; сон 1; сделано | ./c1_task> out.txt

Я абсолютно потерян в этом, и я до сих пор ничего не имею. Я не знаю с чего начать.

Может кто-нибудь мне что-нибудь посоветует, пожалуйста?

Заранее благодарен!

+0

Этот сайт специально для вопросов, а не для общего совета или помощи. –

+0

Если вы используете ОС на базе Linux, проверьте 'man pipe',' man fork' и т. Д. –

+0

Конечно, если вы используете функцию 'fork', я могу с уверенностью предположить, что вы не программируете на окна. :) (Да, я знаю, что есть Cygwin ...) –

ответ

2

Поскольку я не верю в то, чтобы делать для них работу людей, Я не могу дать вам «решение». Я могу, однако, показать вам некоторые из понятий, которые вам нужно знать, чтобы выполнить свое задание. Я также могу дать вам пару ссылок, но если вы просто ищите помощь с концепциями, которые вы не понимаете, вы, скорее всего, найдете необходимую информацию.

Теперь, когда я представил абзац вводной информации, я собираюсь проработать некоторые из понятий, которые вам нужно понять, чтобы решить эту проблему.
Я могу заполнить недостающую информацию, если я получу (и чувствую, что стоит потратить) время, необходимое, чтобы превратить это в псевдо-учебник. :)

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


Первая концепция: вилка() - Инж

Что это?fork() позволяет легко выполнять несколько операций одновременно, дублируя (большую часть) текущего процесса в другой процесс. (На самом деле, это похоже на asexual reproduction.)

Например, ребенка процесс (это новый процесс, который был создан, делая fork() системный вызов) наследует описатели файла (это важный момент!), имеет свою собственную копию переменных, которые родительский процесс (имеет/имел) и т. д.

Пример: Вот пример программы, иллюстрирующей вещь или две. Обратите внимание на wait(). Это делает родительский процесс, который вызвал fork(), ждет, чтобы продолжить выполнение оставшейся части программы до тех пор, пока ребенок не завершится. Без wait(NULL) мы не можем гарантировать, что инструкция родителя printf будет запущена после инструкции printf ребенка.

#include <stdio.h> //the usual, perror 
#include <stdlib.h> //exit 
#include <sys/types.h> //wait()/pid_t 
#include <sys/wait.h> //wait() 
#include <unistd.h> // fork() 

int main() { 
    pid_t cpid; 

    //create our child. 
    //fork() returns -1 if the fork failed, otherwise it returns 
    // the pid of the child to the parent, 
    // and 0 to the child 
    cpid = fork(); 

    //Both the child process and parent process executed the 
    //"cpid =" assignment. 
    //However, they both modified their own version of cpid. 
    //From now on, everything is run by both the child and parent. 

    //the fork failed; there is no child so we're done. 
    if (cpid < 0) { 
     perror("During attempted fork"); 
     exit(EXIT_FAILURE); 
     } 

    //Though the if statement will be checked by both, 
    //cpid will equal 0 only in the child process. 
    if (cpid == 0) { 
     //This will be executed by the child. 
     printf("Hello. I'm your child.\n"); 

     //Now that we've let Pops know that we're alive... 
     exit(EXIT_SUCCESS); 
     } 

    else if (cpid > 0) { 
     //wait for our child to terminate. 
     //I dare you to comment this out & run the program a few times. 
     //Does the parent ever print before the child? 
     wait(NULL); 

     printf("I proudly parented 1 child.\n"); 
     } 

    return 0; 
    } 

Другое: Вы можете увидеть еще один пример here.


Вторая концепция: Трубы

Что такое труба? Труба - это метод межпроцессного взаимодействия. В принципе, у него есть один конец для ввода данных (write() - один из способов сделать это) и один конец, из которого можно получить данные (используя read).

Трубы создаются с использованием системного вызова pipe(). Он возвращает -1 при ошибке. Это только аргумент - это адрес массива из двух ints, который мы назовем pipe_fds.

Если вызов преуспел, первый элемент в pipe_fds содержит file descriptor, который используется для чтения из трубы; второй элемент содержит file descriptor, используемый для записи в трубу.

Вы можете написать на трубу с write() и прочитать с трубы read(). (Более подробную информацию об использовании труб можно найти на various places на the internet.

Вот пример:

#include <stdio.h> //the usual, perror 
#include <stdlib.h> //exit 
#include <sys/types.h> //wait()/pid_t 
#include <sys/wait.h> //wait() 
#include <unistd.h> // fork(), pipe() 

#define BUFLEN 256 //must be greater than one 

int main() { 
    int pipe_fds[2], 
     pipe_ret; 
    pid_t cpid; 

    //Let's create a pipe. 
    //Note that we do this *before* forking so that our forked child 
    // has access to the pipe's file descriptors, pipe_fds. 
    pipe_ret = pipe(pipe_fds); 

    //we couldn't create our pipe 
    if (pipe_ret == -1) { 
     perror("Pipe Creation"); 
     exit(EXIT_FAILURE); 
     } 

    //create our child. 
    cpid = fork(); 

    //the fork failed; there is no child so we're done. 
    if (cpid < 0) { 
     perror("During attempted fork"); 
     exit(EXIT_FAILURE); 
     } 

    //Am I the child? 
    if (cpid == 0) { 
     //close the childs read end of the pipe. 
     //Failing to close unused pipe ends is life or death! 
     //(Check `man 7 pipe`) 
     close(pipe_fds[0]); 

     //Send a message through the pipe. 
     //NOTE: For simplicity's sake, we assume that our printing works. 
     // In the real world, it might not write everything, etc. 
     //We could use `write()`, but this way is easier. 
     dprintf(pipe_fds[1], "Daddy, I'm alive.\n"); 

     //We're done writing. Close write end of the pipe. 
     //This is the wise thing to do, but it would get closed anyways. 
     close(pipe_fds[1]); 

     //Now that we've let Pops know that we're alive... 
     exit(EXIT_SUCCESS); 
     } 

    else if (cpid > 0) { 
     char buf[BUFLEN] = {}; 
     int bytes_read = 0; 

     //close *our* write end of the pipe. Important! 
     //Comment this out and watch your program hang. 
     //Again, check out `man 7 pipe`. 
     close(pipe_fds[1]); 

     //read data from pipe until we reach EOF 
     while ((bytes_read = read(pipe_fds[0], buf, BUFLEN - 1)) > 0) { 
      //null terminate our string. 
      //(We could use snprintf instead...) 
      buf[bytes_read] = '\0'; 

      //You can comment this out to prove to yourself that 
      //we're the one printing the child's message. 
      printf("%s", buf); 
      } 

     //close read end of pipe 
     close(pipe_fds[0]); 

     //wait for our child to terminate. 
     wait(NULL); 

     printf("I proudly parented 1 child.\n"); 
     } 

    return 0; 
    } 

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

Читайте и экспериментируйте с примерами. Примечания в комментариях помогут вам узнать.

+0

Спасибо за этот ответ, человек, помог много. Я уже закончил домашнюю работу, теперь все это имеет смысл, и я нахожу это довольно простым и логичным: D Если кто-нибудь увидит код, вот окончательная, полностью работающая версия http://pastebin.com/tgGNf3Fb (c1task is другая программа, которая считывает строки из stdin до EOF (каждая строка содержит два натуральных числа, разделенных пробелом) и находит (записывает в stdout) самый большой общий делитель этих двух чисел или записывает строку «prime» на stdout, если числа BOTH являются основными). – hofiisek

+0

@hofiisek: Я рад, что это сработало для вас ... (Надеюсь, ты получишь хороший класс.: D) –

+0

хе-хе, спасибо .. :) но мне все равно, о классах, особенно в этом классе .. прошел проходит: D – hofiisek