прочитать последнюю строку fifo

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

Я не могу придумать чистый способ сделать это, есть идеи?

РЕДАКТИРОВАТЬ: процесс записи никогда не остановит запись строк в fifo. То, что я имею в виду под последней строкой, является последним к тому времени, когда я читаю fifo. За ним не обязательно следует EOF.


person Ben    schedule 21.02.2010    source источник
comment
Что вы подразумеваете под «последней строкой»? pipe (он же fifo) это поток, а не файл, читая строку не знаешь последняя ли она или какие то данные будут доступны позже.   -  person qrdl    schedule 21.02.2010
comment
Последняя строка, записанная в конвейер в процессе записи, является самой актуальной информацией. Вот почему, когда я собираю информацию, я хочу самую новую.   -  person Ben    schedule 21.02.2010


Ответы (3)


Если вас больше всего беспокоит блокировка чтения, откройте FIFO как неблокирующий. Я предполагаю, что вы знаете, что ищете в потоке, и просто отбросите все, что было раньше.

Вы также можете использовать что-то вроде select(), чтобы получать информацию, когда есть что прочитать с трубы.

person Duck    schedule 21.02.2010

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

В этом случае мой подход был бы таким: установить неблокирующий режим для дескриптора fifo, используя флаг O_NONBLOCK для системного вызова fcntl(), и использовать что-то вроде этого:

while (!exit_condition) {
    bytes = read(fd, wrkbuf, sizeof(wrkbuf));  // error handling omitted
    if (0 == bytes && bytes_to_process > 0) {
        process(wrkbuf, bytes_to_process);
        bytes_to_process = 0;
    } else
        bytes_to_process = bytes;
}
person qrdl    schedule 21.02.2010

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

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

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

person jfawcett    schedule 21.02.2010