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