LINUX.ORG.RU

Процесс выводит сообщение два раза

 , ,


0

1

Здравствуйте. Разбираюсь с процессами в linux. С-но есть задача - несколько процессов по очереди создают друг-друга и общаются различным способом(fifo, pipe и т.п.) Зеленый процесс создает желтый, тот фиолетовый, а тот - оранжевый. Оранжевый читает со стандартного потока список файлов в директории, узнает их количество и передает желтому через fifo

т.е. З->Ж->Ф->О

прогу компилирую с помощью файла, который содержит следующие инструкции:

#!/bin/bash
clear
echo "--------"
echo ""
gcc code.cpp -o proga -pthread
ls -1 |./proga
echo ""
echo "--------"

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

т.е.должно быть так

------
сообщения процессов
читаем из fifo
сообщения процессов
-----

а выглядит так:

------
сообщения процессов
-----
читаем из fifo
читаем из fifo
сообщения процессов

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

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

int main()
{

   int     fifo;//дескриптор. будет использоваться для чтения-записи fifo
   char    fifo_string[MAX_BUFER_SIZE];//строка для чтения из fifo
   char    fifo_name[] = "aaa.fifo";//имя канала
   ssize_t size;

  //стартует зеленый процесс

  green_process=getpid();

  fprintf(stderr, "GREEN:\tработает зеленый процесс, его id:  %d \n", green_process);

  yellow_process=fork();

  switch(yellow_process)
  {
    case -1:
      critical_error("Ошибка работы желтого процесса");
      break;

    case 0://значит это желтый процесс
      yellow_process=getpid();
      fprintf(stderr, "YELLOW:\tработает желтый процесс, его id:  %d \n", yellow_process);

        //стартуем фиолетовый процесс
      purple_process=fork();

      switch(purple_process)
      {
        case -1:
          critical_error("Ошибка создания фиолетового процесса");
          break;

        case 0://значит это фиолетовый процесс
          purple_process=getpid();
          fprintf(stderr, "PURPLE:\tработает фиолетовый процесс, его id:  %d \n", purple_process);
          break;

        default://продолжает работать желтый процесс

        //стартуем оранжевый процесс
        orange_process=fork();

        switch(orange_process)
        {
          case -1:
            critical_error("Ошибка создания оранжевого процесса");
            break;

          case 0://значит это оранжевый процесс
            orange_process=getpid();
            fprintf(stderr, "ORANGE:\tработает оранжевый процесс, его id:  %d \n", orange_process);
            /*
            получает со стандартного
            потока ввода список файлов каталога, и выводит их на экран, добавляя перед
            каждым именем порядковый номер
            */
            fprintf(stderr, "ORANGE:\tполучаем список файлов каталога:\n");
            char *text;
            text=get_strings();

            printf("%s\n", text);

            //вычисляем количество файлов
            int count_files;
            count_files=get_count_strings(text);

            //переводим это число в строку

            char strNumber[MAX_BUFER_SIZE];

            sprintf(strNumber, "%d", count_files);

              //создаем фифо
            if(mkfifo(fifo_name,0666) < 0 && errno != EEXIST)
            {
               critical_error("Ошибка создания FIFO");
            }

            if((fifo = open(fifo_name, O_WRONLY)) < 0)
            {                          
               critical_error("Can't open FIFO for writting");
            }

            size = write(fifo, strNumber, strlen(strNumber));//пишем байты в fifo
           
          
            if(size != strlen(strNumber))//если в fifo не записалась информация, останавливаем программу
            {
                critical_error("Can't write all string to FIFO");
            }

            close(fifo);


            break;

            default:
            //продолжает работать фиолетовый процесс
            fprintf(stderr, "Продолжает работать фиолетовый процесс\n" );

        }
        //продолжает работать желтый процесс
        
        //считываем из fifo информацию оранжевого процесса

        if((fifo = open(fifo_name, O_RDONLY)) < 0)
          {
            critical_error("Can't open FIFO for reading");
          }

          size = read(fifo, fifo_string, MAX_BUFER_SIZE);

          if(size < 0)
          {
            critical_error("Can't read string from FIFO");
          }

          fprintf(stderr, "YELLOW:\t читаем из fifo количество файлов: %s \n", fifo_string);
          

          close(fifo);
        
      }

      break;

    default:
      //продолжает работать зеленый процесс. создаем следующую ветку

      
      fprintf(stderr, "GREEN:\tпродолжает работать зеленый процесс, его id:  %d \n", yellow_process);

  }

   return 0;
}

Завершение программы не означает завершение процессов(!!) порожденных fork. Они вполне могут продолжать работать до и после любого echo.

io ★★ ()

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

io ★★ ()
Ответ на: комментарий от io

вероятно, по логике программы фифо читают как минимум два процесса - оранжевый и желтый.

оранжевый пишет в fifo, желтый читает

gwyllum ()

Нельзя рассчитывать на на определённый порядок при работе параллельных процессов в многозадачной системе. Одновременное использование одного файла(в данном случае терминала, связанного с stdout) несколькими процессами без синхронизации не может привести ни к чему хорошему.

Ну и в частности «жёлтый» может завершиться по ошибке открытия fifo, который мог ещё не успеть создать «оранжевый»

В общем нужны семафоры, циклы с ожиданием, проверками, таймауты и т.п. Без этого нельзя. Иначе программа, казалось бы отлаженная на одноядерной системе, начнёт сбоить на реально многопроцессорной или просто на иначе настроенной ОС.

Elyas ★★★★★ ()
Последнее исправление: Elyas (всего исправлений: 1)
Ответ на: комментарий от Jefail

У нас тоже есть, только её использовать надо. ;) Fixed.

Но простыни лучше, да, куда-нибудь в другое место.

beastie ★★★★★ ()
Ответ на: комментарий от gwyllum

А если подумать?

default://продолжает работать желтый процесс
        //стартуем оранжевый процесс
        orange_process=fork();
        switch(orange_process)
        {
        ...
        case 0://значит это оранжевый процесс
        ...
        close(fifo);
        break;  <<<< тут не exit какой-нибудь! break!
        ...
        }
         }
        //продолжает работать желтый процесс
        хренушки, тут два процесса работают!
        //считываем из fifo информацию оранжевого процесса
io ★★ ()
    default:
      //продолжает работать зеленый процесс. создаем следующую ветку
      fprintf(stderr, "GREEN:\tпродолжает работать зеленый процесс, его id:  %d \n", yellow_process);
  }
   return 0;

Вот тут у тебя зелёный процесс умирает, а все последующие становятся демонами. Как только зелёный процесс умер — bash продолжил работу. Чтобы избежать преждевременной смерти зелёного процесса — сначала похорони детей через wait(NULL)

kim-roader ★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.