基于c 实现 FIFO

功能:

1、读和写长度不限制

2、数据操作 和 指针操作分开(如先操作数据,再操作指针)
     注意:直接操作指针的情况下,注意越界问题,要每次拷贝进入FIFO的数据大小要是FIFO大小的整数分之一
                例子:
                fifo size 是32K 每次读或者写的数据是1K,不会越界

                 如果每次操作3K,则操作导接近FIFO末尾的时候,容易越界
                 如果要解决3K操作问题,不要操作指针, 直接调用 fifo_read fifo_write操作即可

               

适用场景:

单向通信模式,一方写、一方读,可用于任务间单向通信(无需锁)
如:

1、音频各个处理流程间,缓冲数据

2、线程间、进程间,cpu间,基于共享内存的大数据量传递,缓冲数据

头文件:

/*
 * Time       : 2023/12/XX
 * Author     :
 */
#ifndef __ZFIFO_H__
#define __ZFIFO_H__

// #include "stdint.h"
#include "stdio.h"
#include "stdlib.h"

// #define min(a, b) (((a) < (b)) ? (a) : (b))

/* FIFO数据的类型,可以是结构体类型 */
typedef unsigned char u8;
typedef unsigned int u32;

/* 读写偏移计数最大值1取 2*size 长度,解决取 size 大小时,当 w r 重叠时,无法区分满 或者空的问题 */
typedef struct
{
    u32 w;    /* 写偏移计数 */
    u32 r;    /* 读偏移计数 */
    u32 size; /* FIFO数据区大小 */
    u8 *data; /* FIFO数据区指针 */
} fifo_t;

/*
 ****************************************************************
 * 函数功能:FIFO初始化(动态分配内存)
 *
 * *参数 size:fifo数据区字节数
 * *返回值 创建成功:返回创建fifo指针
 *         创建失败:返回创建空指针
 *
 ****************************************************************
 */
fifo_t *fifo_init(u32 size);

/*
 ****************************************************************
 * 函数功能:FIFO内存释放(和动态分配内存初始化配合使用)
 *
 * *参数 f:fifo指针
 * *返回值 0
 *
 ****************************************************************
 */
u32 fifo_deinit(fifo_t *f);

/*
 ****************************************************************
 * 函数功能:FIFO初始化(只初始化)
 *
 * *参数 f:fifo指针
 * *参数 buf:fifo数据区
 * *参数 size:fifo数据区字节数
 * *返回值 0
 *
 ****************************************************************
 */
void fifo_init_ext(fifo_t *f, void *buf, u32 size);

/*
 ****************************************************************
 * 函数功能:FIFO重置
 *
 * *参数 f:fifo指针
 * *返回值 0
 *
 ****************************************************************
 */
u32 fifo_reset(fifo_t *f);

/*
 ****************************************************************
 * 函数功能:获取fifo数据区已使用空间大小
 *
 * *参数 f:fifo指针
 * *返回值 fifo数据区已使用字节数
 *
 ****************************************************************
 */
u32 fifo_getUsed(fifo_t *f);

/*
 ****************************************************************
 * 函数功能:获取fifo数据区空余空间大小
 *
 * *参数 f:fifo指针
 * *返回值 fifo数据区空余字节数
 *
 ****************************************************************
 */
u32 fifo_getFree(fifo_t *f);

/*
 ****************************************************************
 * 函数功能:获取读指针位置
 *
 * *参数 f:fifo指针
 * *返回值 读指针位置
 *
 ****************************************************************
 */
u8 *fifo_getReadPtr(fifo_t *f);

/*
 ****************************************************************
 * 函数功能:获取写指针位置
 *
 * *参数 f:fifo指针
 * *返回值 写指针位置
 *
 ****************************************************************
 */
u8 *fifo_getWritePtr(fifo_t *f);

/*
 ****************************************************************
 * 函数功能:FIFO是否满
 *
 * *参数 f:fifo指针
 * *返回值 1-满 0-未满
 *
 ****************************************************************
 */
u32 fifo_isFull(fifo_t *f);

/*
 ****************************************************************
 * 函数功能:FIFO是否为空
 *
 * *参数 f:fifo指针
 * *返回值 1-空 0-未空
 *
 ****************************************************************
 */
u32 fifo_isEmpty(fifo_t *f);

/*
 ****************************************************************
 * 函数功能:FIFO读数据(不更新读指针)
 *
 * *参数 f:fifo指针
 * *参数 buf:数据缓冲区
 * *参数 len:数据长度
 * *返回值 实际读数据长度
 *        *注意 fifo剩余数据 < len 情况
 *
 ****************************************************************
 */
u32 fifo_readOnlyData(fifo_t *f, u8 *buf, u32 len);

/*
 ****************************************************************
 * 函数功能:更新FIFO读指针(不读数据)
 *
 * *参数 f:fifo指针
 * *参数 len:数据长度
 * *返回值 实际读出数据长度
 *        *注意 fifo剩余数据 < len 情况
 * *注意 整体逻辑同读数据保持一致
 *
 ****************************************************************
 */
u32 fifo_readOnlyPtr(fifo_t *f, u32 len);

/*
 ****************************************************************
 * 函数功能:从FIFO读数据、并更新读指针
 *
 * *参数 f:fifo指针
 * *参数 buf:数据缓冲区
 * *参数 len:数据长度
 * *返回值 实际读出数据长度
 *        *注意 fifo剩余数据 < len 情况
 * *注意 基于 fifo_readOnlyData fifo_readOnlyPtr 实现
 *
 ****************************************************************
 */
u32 fifo_read(fifo_t *f, u8 *buf, u32 len);

/*
 ****************************************************************
 * 函数功能:FIFO写数据(不更新写指针)
 *
 * *参数 f:fifo指针
 * *参数 buf:数据缓冲区
 * *参数 len:数据长度
 * *返回值 实际写数据长度
 *        *注意 fifo剩余数据 < len 情况
 *
 ****************************************************************
 */
u32 fifo_writeOnlyData(fifo_t *f, u8 *buf, u32 len);

/*
 ****************************************************************
 * 函数功能:更新FIFO写指针(不写数据)
 *
 * *参数 f:fifo指针
 * *参数 len:数据长度
 * *返回值 实际写数据长度
 *        *注意 fifo剩余数据 < len 情况
 * *注意 整体逻辑同写数据保持一致
 *
 ****************************************************************
 */
u32 fifo_writeOnlyPtr(fifo_t *f, u32 len);

/*
 ****************************************************************
 * 函数功能:FIFO写数据、并更新写指针
 *
 * *参数 f:fifo指针
 * *参数 buf:数据缓冲区
 * *参数 len:数据长度
 * *返回值 实际写数据长度
 *        *注意 fifo剩余数据 < len 情况
 * *注意 基于 fifo_writeOnlyData fifo_writeOnlyPtr 实现
 *
 ****************************************************************
 */
u32 fifo_write(fifo_t *f, u8 *buf, u32 len);

#endif /* __ZFIFO_H__ */

.c 函数实现:

/*
 * Time       : 2023/12/XX
 * Author     :
 */

#include "fifo.h"
#include "string.h"

/*
 * init
 *
 */
fifo_t *fifo_init(u32 size)
{
    fifo_t *f = (fifo_t *)malloc(sizeof(fifo_t));
    if (NULL == f)
        return NULL;

    f->data = (u8 *)malloc(sizeof(u8) * size);
    if (NULL == f->data)
    {
        free(f);
        return NULL;
    }

    f->w = 0;
    f->r = 0;
    f->size = size;

    return f;
}

void fifo_init_ext(fifo_t *f, void *buf, u32 size)
{
    f->w = 0;
    f->r = 0;
    f->size = size;
    f->data = buf;

    return f;
}

u32 fifo_deinit(fifo_t *f)
{
    if (NULL != f->data)
    {
        free(f->data);
        f->data = NULL;
    }

    if (NULL != f)
    {
        free(f->data);
        // f = NULL;
    }

    return 0;
}

u32 fifo_reset(fifo_t *f)
{
    f->w = 0;
    f->r = 0;

    return 0;
}

u32 fifo_getUsed(fifo_t *f)
{
#if 0
	u32 len;

	if (f->w >= f->r)
	{
		len = f->w - f->r;
	}
	else
	{
		len = (f->size << 1) - f->r + f->w;
	}

	return len;
#else
    if (f->w >= f->r)
    {
        return (f->w - f->r);
    }

    return ((f->size << 1) - f->r + f->w);
#endif
}

u32 fifo_getFree(fifo_t *f)
{
#if 0
	u32 len;

	if (f->w >= f->r)
	{
		len = f->size - f->w + f->r;
	}
	else
	{
		len = f->r - f->w - f->size;
	}

	return len;
#else
    if (f->w >= f->r)
    {
        return (f->size - f->w + f->r);
    }

    return (f->r - f->w - f->size);
#endif
}

u8 *fifo_getReadPtr(fifo_t *f)
{
    return (f->data + (f->r % f->size));
}

u8 *fifo_getWritePtr(fifo_t *f)
{
    return (f->data + (f->w % f->size));
}

u32 fifo_isFull(fifo_t *f)
{
    if (0 == fifo_getFree(f))
        return 1;

    return 0;
}

u32 fifo_isEmpty(fifo_t *f)
{
    if (0 == fifo_getUsed(f))
        return 1;

    return 0;
}

u32 fifo_readOnlyData(fifo_t *f, u8 *buf, u32 len)
{
    // copy len, first copy len
    u32 cl, fcl;

    // 剩余空间 与 待读数据取小
    cl = fifo_getUsed(f);
    if (cl > len) cl = len;

    // 第一次读
    fcl = f->size - (f->r % f->size);
    if (fcl > cl) fcl = cl;

    memcpy(buf, f->data + (f->r % f->size), fcl);

    // 第二次读,跨buf尾的时候,从buf头开始读剩余部分
    if (fcl < cl)
        memcpy(buf + fcl, f->data, cl - fcl);

    return cl;
}

u32 fifo_readOnlyPtr(fifo_t *f, u32 len)
{
    // copy len
    u32 cl = fifo_getUsed(f);
    if (cl > len) cl = len;

    // 计算偏移地址
    f->r = (f->r + cl) % (f->size << 1);

    return cl;
}

u32 fifo_read(fifo_t *f, u8 *buf, u32 len)
{
    u32 ret = 0;

    ret = fifo_readOnlyData(f, buf, len);
    ret |= fifo_readOnlyPtr(f, len);

    return ret;
}

u32 fifo_writeOnlyData(fifo_t *f, u8 *buf, u32 len)
{
    // copy len, first copy len
    u32 cl, fcl;

    // 剩余空间 与 写数据 取小
    cl = fifo_getFree(f);
    if (cl > len) cl = len;

    // 第一次写
    fcl = f->size - (f->w % f->size);
    if (fcl >= cl) fcl = cl;

    memcpy(f->data + (f->w % f->size), buf, fcl);

    // 第二次:buf头开始写剩余部分
    if (fcl < cl)
        memcpy(f->data, buf + fcl, cl - fcl);

    return cl;
}

// 计算逻辑通写数据保持一致
u32 fifo_writeOnlyPtr(fifo_t *f, u32 len)
{
    // copy len
    u32 cl = fifo_getFree(f);
    if (cl > len) cl = len;

    // 计算偏移地址
    f->w = (f->w + cl) % (f->size << 1);

    return cl;
}

u32 fifo_write(fifo_t *f, u8 *buf, u32 len)
{
    u32 ret = 0;

    ret = fifo_writeOnlyData(f, buf, len);
    ret |= fifo_writeOnlyPtr(f, len);

    return ret;
}

测试程序:


#include <stdio.h>  
#include <stdlib.h>  
#include <pthread.h>  
#include <unistd.h>  
#include <fcntl.h>  
#include "fifo.h"
  
#define FIFO_READ_SIZE  32
#define FIFO_WRITE_SIZE 19
#define FIFO_BUF_SIZE   32

fifo_t* g_fifo;
int  g_exit = 0;

// 读文件线程函数  
void* read_file(void* arg) {  
    int fd = *(int*)arg;  
    char buffer[FIFO_WRITE_SIZE + 1];  
    ssize_t bytes_read;  
  
    while(1)
    {
        if(fifo_getFree(g_fifo) >= FIFO_WRITE_SIZE)
        {
            if ((bytes_read = read(fd, buffer, FIFO_WRITE_SIZE)) > 0) {  
                if(bytes_read != fifo_write(g_fifo, buffer, bytes_read))
                {
                    printf("write fifo error\n");
                }
                // if(bytes_read != FIFO_WRITE_SIZE)
                //     printf("\n ## len = %d\n", (int)bytes_read);
            }
            else
            {
                printf("write fifo finish\n");
                g_exit = 1;
                break;
            }
        }
        else
        {
            usleep(2000);
        }
    }
  
    return NULL;  
}  
  
// 写文件线程函数  
void* write_file(void* arg) {  
    int fd = *(int*)arg;  
    char buffer[FIFO_READ_SIZE + 1];  
    ssize_t bytes_written;
    int fifo_size = 0;

    while(1)
    {
        fifo_size = fifo_getUsed(g_fifo);
        if(fifo_size >= FIFO_READ_SIZE)
        {
            if (FIFO_READ_SIZE != fifo_read(g_fifo, buffer, FIFO_READ_SIZE))
            {
                printf("read fifo error\n");
            }
            else
            {
                write(fd, buffer, FIFO_READ_SIZE);
            }

        }
        else if(fifo_size >= 0)
        {
            if (fifo_size != fifo_read(g_fifo, buffer, fifo_size))
            {
                printf("read fifo error\n");
            }
            else
            {
                write(fd, buffer, fifo_size);
            }
        }
        else
        {
            usleep(2000);
        }

        if(fifo_isEmpty(g_fifo) && g_exit) 
        {
            printf("read fifo finish\n");
            break;
        }
    }
    return NULL;  
}  
  
int main() {  
    pthread_t read_thread, write_thread;  
    int fd_in, fd_out;

    g_fifo = fifo_init((u32)FIFO_BUF_SIZE); 

    // 打开输入文件和输出文件  
    fd_in = open("input.txt", O_RDONLY);  
    fd_out = open("output.txt", O_WRONLY | O_CREAT | O_TRUNC, 0666);  
  
    // 创建读文件线程和写文件线程  
    pthread_create(&read_thread, NULL, read_file, &fd_in);  
    pthread_create(&write_thread, NULL, write_file, &fd_out);  
  
    // 等待两个线程执行完毕  
    pthread_join(read_thread, NULL);  
    pthread_join(write_thread, NULL);  
  
    // 关闭文件描述符  
    close(fd_in);  
    close(fd_out);  

    fifo_deinit(g_fifo);
  
    return 0;  
}

  • 8
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值