linux kfifo移植到应用层

本文介绍了如何在应用层使用内核kfifo无锁队列进行数据在两个线程间的高效传递,并着重于改造后的数据报形式,避免了粘包问题。作者提供了头文件、实现细节和使用示例,展示了Kfifo的使用方法和优化技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近由于项目需要在两个线程之间传递数据,就想到了内核的kfifo无锁队列,于是移植到应用层。为了使用更加方便,添加了拆包功能。原生的kfifo是字节流类型,改造之后变成了数据报类型。就是说接收方获取数据的时候要么是获取到一个完整的数据报,要么就什么都没获取到。不会有粘包问题。

头文件:

#ifndef _NO_LOCK_QUEUE_H_
#define _NO_LOCK_QUEUE_H_

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <string>
#include <iostream>
using namespace  std;

struct mypackage
{
	unsigned int len;
	unsigned char data[0];
};


class Kfifo
{
public:
	Kfifo(unsigned int  isize);
	~Kfifo();
	unsigned int get(unsigned char* buffer, unsigned int len);
	unsigned int getvalue(unsigned char* buffer, unsigned int len);
	unsigned int put(const unsigned char* buffer, unsigned int len);
	unsigned int usedsize();
	unsigned int packlen();
	unsigned int getsize() { return size; };
	bool packavaliable();

	unsigned int getpack(unsigned char* buffer, unsigned int len);
	unsigned int putpack(mypackage* pack);
	unsigned int putpack(const unsigned char* _buffer, unsigned int len);
	static unsigned long roundup_power_of_two(unsigned long val);
private:
	inline bool is_power_of_2(unsigned long n)
	{
		return (n != 0 && ((n & (n - 1)) == 0));
	};
	inline unsigned int unused()
	{
		return size - (in - out);
	}

private:
	unsigned int size;
	unsigned int in;
	unsigned int out;
	unsigned int	mask;
	unsigned char* buffer;
};


#endif

实现文件:

#include "kfifo.h"

Kfifo::~Kfifo()
{
	if (buffer) free(buffer);
	size = in = out = 0;
}
unsigned long Kfifo::roundup_power_of_two(unsigned long val)
{
	if (val & (val - 1) == 0)
	{
		return val;
	}
	unsigned long maxulong = (unsigned long)((unsigned long)~0);
	unsigned long andv = ~(maxulong & (maxulong >> 1));
	while ((andv & val) == 0)
		andv = andv >> 1;
	return andv << 1;
}
Kfifo::Kfifo(unsigned int isize) :size(isize), in(0), out(0), mask(size - 1)
{
	if (!is_power_of_2(isize))
	{
		size = roundup_power_of_two(isize);
	}
	buffer = (unsigned char*)malloc(isize);
}

unsigned int Kfifo::get(unsigned char* _buffer, unsigned int len)
{
	unsigned int l;
	len = min(len, in - out);


	l = min(len, size - (out & (size - 1)));
	memcpy(_buffer, buffer + (out & (size - 1)), l);
	memcpy(_buffer + l, buffer, len - l);

	unsigned char(*vec)[256] = (unsigned char(*)[256])buffer;

	out += len;
	return len;

}
unsigned int Kfifo::getvalue(unsigned char* _buffer, unsigned int len)
{
	unsigned int l;
	len = min(len, in - out);

    __sync_synchronize();

	l = min(len, size - (out & (size - 1)));
	memcpy(_buffer, buffer + (out & (size - 1)), l);
	memcpy(_buffer + l, buffer, len - l);

    __sync_synchronize();

	return len;

}
unsigned int Kfifo::put(const unsigned char* _buffer, unsigned int len)
{
	unsigned int l;
	len = min(len, size - in + out);

    __sync_synchronize();

	l = min(len, size - (in & (size - 1)));
	memcpy(buffer + (in & (size - 1)), _buffer, l);
	memcpy(buffer, _buffer + l, len - l);

    __sync_synchronize();

	in += len;
	return len;

}
unsigned int Kfifo::usedsize()
{
	return in - out;
};
bool Kfifo::packavaliable()
{
	
	if (usedsize() < sizeof(mypackage))
	{
		return false;
	}

	unsigned int pack_len = packlen();
	unsigned char(*vec)[1024] = (unsigned char(*)[1024])buffer;
	
	return (usedsize() >= pack_len);
}

unsigned int Kfifo::putpack(mypackage* pack)
{
	if (unused() < pack->len)
		return 0;
	return put((unsigned char*)pack, pack->len);

};

unsigned int Kfifo::putpack(const unsigned char* _buffer, unsigned int len)
{
	unsigned int head_len = sizeof(mypackage);
	unsigned int total_len = len + head_len;
	if (unused() < total_len)
		return 0;
	
	put((unsigned char*)&total_len, head_len);
	return put(_buffer, len);

};

unsigned int Kfifo::getpack(unsigned char* outbuffer, unsigned int len)
{
	if (!packavaliable())
		return 0;
	unsigned int pack_len = packlen();

	if (pack_len > len)
		return 0;

	return get(outbuffer, pack_len);
}

unsigned int Kfifo::packlen() {
	unsigned int len;
	if (getvalue((unsigned char*)&len, sizeof(len)) == 0)
		return 9;
	return len;
	
};

使用示例:

void testkfifosent(Kfifo* fifo)
{
    static int count = 0;
    unsigned char buf[100];
    
    unsigned int len;
    while (1)
    {
        for (int i = 0; i < 100; i++)
        {
            
            buf[i] = i;
            count++;
        }
        //mypackage* pack = (mypackage*)&buf;
        //pack->len = 100;
        len = fifo->putpack(buf,sizeof(buf));
    }
}

void testkfiforecv(Kfifo* fifo)
{

    unsigned char recvbuf[200];
    unsigned int len;
    while (1)
    {
        len = fifo->getpack(recvbuf, 200);
        
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值