Вопрос об pipes

Тема в разделе "WASM.WIN32", создана пользователем Fess exe, 3 ноя 2004.

  1. Fess exe

    Fess exe New Member

    Публикаций:
    0
    Регистрация:
    24 май 2004
    Сообщения:
    19
    Адрес:
    Russia
    Есть дочерний консольный процесс. Мой процесс пишет в его input handle и читает из его output handle и handle вывода ошибок через анонимные пйпы. При чтении таким образом



    DWORD written;

    while(true)

    {

    written=0;

    RtlZeroMemory(ReadBuf,4048); // ReadBuf - массив из 4048 байтов

    if((!ReadFile(hRead,ReadBuf,4048,&written,NULL)))

    {

    errmsg();

    return;

    }

    if(!written)

    {

    return;

    }

    if(!ReadBuf[0])

    {

    return;

    }

    else

    {

    /*

    Чтение из буфера

    */

    }

    }





    программа виснет, вероятнее всего потому, что ReadFile натыкается на то, что консоль ждёт ввода, после чего останавливается. Как сделать так, чтоб программа не висла, а останавливалвсь? То есть как узнать завершил ли дочерний прцесс обработку введённого или нет?
     
  2. q_q

    q_q New Member

    Публикаций:
    0
    Регистрация:
    5 окт 2003
    Сообщения:
    1.706
    Fess exe

    Дочерний процесс твой или любой?
     
  3. Pavia

    Pavia Well-Known Member

    Публикаций:
    0
    Регистрация:
    17 июн 2003
    Сообщения:
    2.409
    Адрес:
    Fryazino
    Твоя программа ждет пока дочерний процесс выведет 4048 байт.

    В MSDN все описано и есть пример, как работать с анонимными каналами(pipes).

    То есть как узнать завершил ли дочерний прцесс обработку введённого или нет?

    Такого сделать нельзя. Но можно узнать сколько на данной момент байт было выведено на паток.

    PeekNamedPipe(hRead,nul, 0, &bread, &avail, nul);

    if (avail>0)

    {

    Читаем данные

    }

    В avail лижит число байт выведенных на поток.

    Проверяй на закрытие потока.

    exit=0;

    GetExitCodeProcess(pin.hProcess,exit);

    if (exit <> STILL_ACTIVE)

    {

    выходим из вечного цыкла

    }
     
  4. Fess exe

    Fess exe New Member

    Публикаций:
    0
    Регистрация:
    24 май 2004
    Сообщения:
    19
    Адрес:
    Russia
    q_q

    Процесс дочерний мой.



    Pavia

    То есть только с именованными пайпами или эта функция(PeekNamedPipe) и для анонимных работает?
     
  5. IceStudent

    IceStudent Active Member

    Публикаций:
    0
    Регистрация:
    2 окт 2003
    Сообщения:
    4.300
    Адрес:
    Ukraine
    Fess exe

    Читаем описание функции.
     
  6. Fess exe

    Fess exe New Member

    Публикаций:
    0
    Регистрация:
    24 май 2004
    Сообщения:
    19
    Адрес:
    Russia
    Ага, прочёл, каюсь.

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

    Или я опять что-то пропустил?
     
  7. IceStudent

    IceStudent Active Member

    Публикаций:
    0
    Регистрация:
    2 окт 2003
    Сообщения:
    4.300
    Адрес:
    Ukraine


    Что-то я не понял.

    avail станет равным 0 после вызова ReadFile, которая и опустошит буфер трубы (pipe).



    .

    Используем ReadFile с заполненной структурой OVERLAPPED.

    В этом случае поток останавливается до тех пор, пока в трубе (pipe) не появятся данные. Этот момент сигнализируется двумя событиями: возвращается управление из ReadFile и сигнализируется событие (hEvent) в OVERLAPPED. Но нет гарантии, что консольная программа что-то выдаст и поток проснётся.



    Чтобы избежать этого, с PeekNamedPipe можно сделать так:
    Код (Text):
    1.  
    2. // 1) посылаем данные в консоль.
    3. // нужно точно узнать, что именно ожидает консольная программа:
    4. // - некий завершающий символ (';','\r\n','\n'...)
    5. // - нажатие какой-то клавишы (редко, на бывает)
    6. bResult = WriteFile(hWrite,lpBuf,dwBuf,lpWritten,NULL);
    7. nAvail = 0;
    8. // пока не появятся данные в трубе
    9. while(!nAvail){
    10.   // делаем что-то полезное (следим за временем), просто спим
    11.   Sleep(200);
    12.   // проверяем наличие данных в трубе
    13.   bResult = PeekNamedPipe(hRead,NULL, 0, &nRead, &nAvail, NULL);
    14.   }
    15. // на то случай, если вышли из цикла по своей надобности
    16. if (nAvail){
    17.   // здесь читается буфер фиксированного размера
    18.   // можно также читать сразу весь буфер трубы:
    19.   // ReadFile(hRead,lpBuf,nAvail,&nRead,NULL);
    20.   Result = ReadFile(hRead,lpBuf,dwBuf,&nRead,NULL);
    21.   }
    22.  






    Это зависит от самого процесса — как именно он завершает обработку введённого: начинает выводить результат сразу весь или потихоньку по чуть-чуть (например, показывая текущее состояние обработки).

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



    Но все эти условия зависят от самого консольного приложения…
     
  8. Fess exe

    Fess exe New Member

    Публикаций:
    0
    Регистрация:
    24 май 2004
    Сообщения:
    19
    Адрес:
    Russia
    Привидённый выше пример кода меня несколько смущает, ибо прграмма так тоже зависнет, если консоль остановиться и будет ждать ввода.
     
  9. Fess exe

    Fess exe New Member

    Публикаций:
    0
    Регистрация:
    24 май 2004
    Сообщения:
    19
    Адрес:
    Russia
    Неужели я написал что-то такое, что настолько ошеломило всех своей гениальностью или тупостью, что никто не может ничего по этому поводу сказать?