Перечитывание из именованного канала, когда писатели приходят и уходят - PullRequest
3 голосов
/ 19 января 2010

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

Я резюмировал это в следующем коде.

int main( int c, char *v[] )
{
    int rfd;
    if ( (rfd = open( PIPENAME, O_RDONLY | O_NONBLOCK )) < 0 )
    {
        perror( "open" );
        return 1;
    }

    char buffer[ 1024000 ];

    // used to give select an upper bound on number of fds
    int nfd = rfd + 1;

    fd_set rfds;
    FD_ZERO( &rfds );
    FD_SET( rfd, &rfds );

    while( true )
    {
        int nr = select( nfd, &rfds, NULL, NULL, NULL );

        if ( nr < 0 )
        {
            perror( "select" );
            break;
        }

        if ( FD_ISSET( rfd, &rfds ) )
        {
            //std::cout << "RFD SET" << std::endl;
            // Ok, we have data we can read
            int nread = read( rfd, buffer, sizeof( buffer ) );
            if ( nread < 0 )
            {
                perror( "read" );
                break;
            }
            else if ( nread == 0 )
            {
                std::cout << "read 0" << std::endl;
            }
            else
            {
                std::cout << "read " << nread << " bytes" << std::endl;

            }

        }
    }

    close( rfd );

    return 0;
}

Проблема, с которой я столкнулся, заключается в том, что после того, как первый процесс записывает в именованный канал и отключает (закрывает) его конец, моя программа не блокируется при выборе. Он фактически имеет установленное значение rfd, и чтение возвращает нулевые байты, считанные в узком цикле.

Мне нужно, чтобы rfd находился в режиме NON_BLOCKING, иначе открытие будет блокироваться, пока не появится писатель.

Я пытался использовать fcntl, чтобы установить режим BLOCKING, но это тоже не работает.

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

Я бросаюсь на твою коллективную мудрость :) Марк.

Ответы [ 3 ]

4 голосов
/ 19 января 2010

ОК, я придумала одно решение, но я не очень довольна им. Это немного «молоток, чтобы сломать орех», если вы спросите меня.

.....
else if ( nread == 0 )   
{   
    std::cout << "read 0" << std::endl;   

    FD_ZERO( &rfds );
    close( rfd );
    if ( (rfd = open( PIPENAME, O_RDONLY | O_NONBLOCK )) < 0 )
    {
        perror( "re-open" );
        break;
    }
    FD_SET( rfd, &rfds );
    nfd = std::max( wfd, rfd ) + 1;
}   
else
.....

По сути, я закрываю и снова открываю трубу.

Я бы все равно приветствовал лучшее решение.

1 голос
/ 05 февраля 2015

Найдено в другом посте:

if ( (rfd = open( PIPENAME, O_RDWR | O_NONBLOCK )) < 0 )

то есть открытие RDWR вместо RDONLY, похоже, работает ...

0 голосов
/ 19 января 2010

Вы пытались открыть fds в неблокирующем режиме, и когда ваш read() возвращает EWOULDBLOCK / EAGAIN, делая clearerr() на fd?

...