如何在C中不断读取FIFO

时间:2014-12-12 13:54:06

标签: c fifo

我想在C中不断读取一个fifo管道。 我的代码示例有效,但是因为我使用while(1)我的一个CPU核心始终是100%。

所以我的问题:是否有更顺畅的方式来读取fifo,而不会杀死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;
}

2 个答案:

答案 0 :(得分:2)

您有3种方法可以处理它: -

  1. 您可以在从FIFO读取时使用阻止模式。

  2. 最简单的方法是在while循环中使用sleep()暂停线程一段时间,这会暂时减少cpu负载。

  3. 您可以使用信号&amp;中断,写入器可以在向FIFO写入内容时发送信号。读取器可以被挂起,直到从FIFO和FIFO的写入器接收到信号。执行读操作直到FIFO结束并再次暂停。

答案 1 :(得分:1)

在这种情况下,我会使用select()进行投票。你可以这样做:

#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;
}

它应该适用于使用mkfifo()创建的FIFO文件。 您还可以在函数调用中使用NULL而不是timeout设置无限超时。

这将大大降低CPU利用率,并允许您只读取实际数据。 请注意,如果您使用简单文件而不是FIFO,select()函数将永远等待它更新,因为简单文件随时可以读取。

您还可以阅读以下文章以获取更多信息:select, pselect, poll

相关问题