Правильный код - неблокирующая труба с попой

Существует множество вопросов о неблокирующих каналах, но НЕТ примеров кода, который можно скопировать и вставить (с небольшими исправлениями) и использовать.

Я получил идею и источники из этой темы: Неблокирующая труба с помощью popen?

Но как это использовать? В while цикл? Пожалуйста, просмотрите мои изменения. Это действительно нужно использовать errno == EAGAIN & дополнительный заголовок #include <cerrno>? Предложите свою лучшую версию, если нужно:

    FILE *pipe;
    char buff[512];
    if ( !(pipe = popen( command.c_str(), "r")) ) return false;

    int d = fileno(pipe);   
    while ( true )
    {
        ssize_t r = read(d, buff, sizeof(buff));
        if (r == -1 && errno == EAGAIN) // really need errno? 
            continue;
        else if (r > 0)
            ptr_output->append(buff);       
        else
            break;
    }

    pclose(pipe);

2 ответа

Решение

Да. Если read вызов возвращается со значением ошибки (-1) и errno установлен в EAGAINэто означает, что данные недоступны, поэтому вы continue цикл, чтобы попробовать еще раз. Если вы избавились от errnoошибки будут эффективно игнорироваться, и ваша программа, вероятно, будет аварийно завершена. Представьте, что вы удалили его: когда read возвращенный -1Но, скажем, ошибка состояла в том, что канал был сломан (другой конец закрыл его), вы просто продолжали бы пытаться зацикливаться и входить в бесконечный цикл. Плохая идея.

В моем многопоточном приложении Linux (Ubuntu 16.04, x86_64, Native POSIX Threads, libc.so.6 версия Ubuntu GLIBC 2.23-0ubuntu9) этот код

int fd = fileno(pipe);
fcntl(fd, F_SETFL, O_NONBLOCK);
while (true)
        {
            ssize_t r = read(fd, buff, sizeof(buff));
            if ((r == -1) && (errno == EAGAIN)) // really need errno?
                continue;
            else
            {
                if (r > 0)
                    result += buff;
                else
                    break;
            }
        }

даже с fctnl(...) причины сбоя, поскольку часто читаются не только выходные данные команды, но и многие другие произвольные значения из ОЗУ. Я думаю, что это связано с поточностью кода.

(Пример: выполнить echo 3 значения, 10, 30 и 40, параллельно 20 нитями, read значения и отображать только последнее значение. Выход: 40 QIh MIh 40 40 30...)

Другой код из этого ответа работает нормально из-за fgets реализация является поточно-ориентированной:

while (!feof(pipe))
{
    if (fgets(buff, sizeof(buff), pipe) != NULL)
    result += buff;
}
Другие вопросы по тегам