FIFO的数组实现方式

来源:互联网 发布:考研网络辅导班 编辑:程序博客网 时间:2024/05/01 02:30

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 1024static 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队列--一些认识

0 0
原创粉丝点击