FIFO的数组实现方式

1 背景

    在Linux中,可以使用库函数mkfifo()创建FIFO,然后可以使用read()/write()系统调用来对其进行读/写操作。然而,如果读写操作比较频繁(例如不同线程间需要不断的传输数据),则会使得程序的效率比较低(由于需要频繁的执行系统调用read()/write())。因此,如果能够使用数组来实现FIFO,则对提高程序的效率具有重要的意义。

2 实现方法

    根据上述背景,参考资料[1]给出了相应的实现方法,但是并没有很好的解决下标循环的问题(即不能保证所读取的是最早进入队列的数据,甚至有可能是最新的)。

2.1 读写单个字符

    见《Linux多线程编程》第4章实例。

2.2 读写多个字符

    根据参考资料[1],实现了一次读写多个字符的版本如下。

#include <stdio.h>
#include <stdint.h>
#include <pthread.h>
#include <unistd.h>
#include <string.h>
#include <stdbool.h>

#define FIFO_LENGTH 1024
static char fifo_buffer[ FIFO_LENGTH ];
static uint16_t front = 0;
static uint16_t rear = 0;

static void *write_thread( void* );
static void *read_thread( void* );
static bool fifo_write( char* buffer, uint16_t wr_len );
static bool fifo_read(char* buffer, uint16_t rd_len );

static pthread_rwlock_t q_lock;

int main(int argc, char*argv[])
{
	pthread_t wr_th;
	pthread_t rd_th;

	pthread_rwlock_init( &q_lock, NULL);
	
	pthread_create( &wr_th, NULL, write_thread, NULL );
	pthread_create( &rd_th, NULL, read_thread, NULL );
	pthread_join(wr_th, NULL);
	pthread_rwlock_destroy( &q_lock );
	return 0;
}


void *write_thread( void*arg )
{
	int i;

	char buffer[] = "0123456789abcdefg";
	for( i = 0; i < 1000; i++) {
		if ( !fifo_write( buffer, sizeof( buffer ) - 1 ) )
			fprintf(stderr, "fifo_write error\n");
		sleep( 1 );
	}
	return (void*)0;
}


void *read_thread( void*arg )
{
	char buffer[10];
	while( 1 ) {
		memset(buffer, 0, 10);
		if ( fifo_read( buffer, 10) )
			printf("%s\n", buffer);
		else
		{
			usleep( 1000 );
		}
	}
	return (void*)0;
}


bool fifo_write( char* buffer, uint16_t wr_len )
{
	if (wr_len > FIFO_LENGTH -1)
		return false;
	
	uint16_t empty_len;
	uint16_t tmp_addr;
	uint16_t tmp_len;

	empty_len = ( front + FIFO_LENGTH - ( rear + 1) ) % FIFO_LENGTH;
	if ( empty_len >= wr_len )
	{
		 // wr_lock
		 pthread_rwlock_wrlock( &q_lock );

		 tmp_addr = ( rear + wr_len) % FIFO_LENGTH;
		 if (tmp_addr <= rear)  //If Circular array have inverse to begin.
		 {
			  tmp_len = wr_len - tmp_addr;
			  memcpy(&fifo_buffer[ rear ], buffer, tmp_len);   //bug place
			  memcpy(&fifo_buffer[0], buffer + tmp_len, tmp_addr);    
		 }
		 else
		 {
			  memcpy(&fifo_buffer[ rear ], buffer, wr_len);
		 }
		 
		 rear = tmp_addr;

		 // unlock
		 pthread_rwlock_unlock( &q_lock );
		 return true;
	}
	return false;
}

bool fifo_read(char*buffer, uint16_t rd_len )
{
     uint16_t valid_len;
     uint16_t tmp_addr;
     uint16_t tmp_len;

     valid_len = ( rear + FIFO_LENGTH - front ) % FIFO_LENGTH;
     
	 if ( valid_len >= rd_len)
     {
		 pthread_rwlock_wrlock( &q_lock );
         
		 tmp_addr = ( front + rd_len ) % FIFO_LENGTH;
         if ( tmp_addr <= front ) 
         {
			 tmp_len = rd_len - tmp_addr;
			 memcpy( buffer, &fifo_buffer[ front ], tmp_len);
			 memcpy( buffer + tmp_len, &fifo_buffer[ 0 ], tmp_addr);     
         }
         else
         {
			 memcpy( buffer, &fifo_buffer[ front ], rd_len );
         }
         front = tmp_addr;
		 
		 pthread_rwlock_unlock( &q_lock );
		 return true;
	 }
	 	
	 return false;
}


参考资料

[1]C语言循环数组做FIFO队列--一些认识

你可能感兴趣的:(FIFO的数组实现方式)