How to constantly read FIFO in C

守給你的承諾、 提交于 2019-12-11 03:22:13

问题


I want to read a fifo pipe constantly in C. My code example works, but since i use while(1) one of my CPU cores is at 100% all the time.

So my question: Is there a smoother way to read the fifo, without killing the CPU?

#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdbool.h>

bool suffix (char* base, char* str) {
    int blen = strlen(base);
    int slen = strlen(str);
    return (blen >= slen) && (0 == strcmp(base + blen - slen, str));
}

bool prefix(const char *pre, const char *str)
{
    return strncmp(pre, str, strlen(pre)) == 0;
}


void chomp(char *s) {
    while(*s && *s != '\n' && *s != '\r') s++;
    *s = 0;
}

int main(int argc, char *argv[])
{
    int fifo, c=0;
    char buf[200];

    char fifo_name[] = "/var/log/proftpd_log_all.fifo";
    fifo = open(fifo_name, O_RDONLY|O_NONBLOCK);

    while (1)
    {
        if (read(fifo, &buf, sizeof(char)*200) > 0)
        {
            if (prefix("[STOR]",buf)) {
                //printf("%s \n", buf);
                if (strstr(buf, ".jpf") != NULL) {
                    //...
                }       
            }
        }
    }
    printf("exit");
    close(fifo);
    return 0;
}

回答1:


You have 3 methods for handling it:-

  1. You can use Blocking mode while reading from FIFO.

  2. Simplest method is to use sleep() within the while loop to suspend the thread for sometime , this would reduce cpu load momentarily.

  3. You can use signals & interrupts,writer can send a signal whenever it writes something to FIFO.The reader can be suspended until a signal is received from the writer of FIFO & performs the read operation until end of FIFO and suspends again.




回答2:


In this case I'd use select() for polling. You can do it like this:

#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <sys/select.h>

int main()
{
    fd_set readCheck;
    fd_set errCheck;
    char buffer[64];
    struct timeval timeout;
    int rv;

    int fd = open("./fifo.test", O_RDONLY | O_RSYNC);

    FD_ZERO(&readCheck);
    FD_ZERO(&errCheck);

    while (1) {
        FD_SET(fd, &readCheck);
        FD_SET(fd, &errCheck);

        timeout.tv_sec = 1;
        timeout.tv_usec = 0;

        rv = select(fd, &readCheck, NULL, &errCheck, &timeout);
        if (rv < 0) {
            printf("Select failed\r\n");
            break;
        }

        if (FD_ISSET(fd, &errCheck)) {
            printf("FD error\r\n");
            continue;
        }

        if (FD_ISSET(fd, &readCheck)) {
            memset(buffer, 0, sizeof(buffer));
            rv = read(fd, buffer, sizeof(buffer));
            if (rv < 0) {
                printf("Read failed\r\n");
                break;
            }
            buffer[63] = '\0';
            printf(buffer);
        }
    }
    close(fd);

    return 0;
}

It should work for FIFO files, created with mkfifo(). You can also set infinite timeout with NULL instead of timeout in function call.

This will reduce your CPU utilization greatly and will allow you to read only real data. Take note that if you use a simple file instead of a FIFO the select() function will wait forever for it to update, because simple files are always ready to read.

You can also read the following mans for more info: select, pselect, poll



来源:https://stackoverflow.com/questions/27445172/how-to-constantly-read-fifo-in-c

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!