├── Makefile ├── README.md ├── doc ├── 111.jpg ├── 2222.jpg └── 33333.jpg ├── main.c ├── notify_main.c └── ring_queue.h /Makefile: -------------------------------------------------------------------------------- 1 | ALL: ring_example notify_ring_example 2 | ring_example: 3 | g++ -g -o ring_test main.c -lpthread -fpermissive 4 | notify_ring_example: 5 | g++ -g -o notify_ring_test notify_main.c -lpthread -fpermissive 6 | clean: 7 | rm -f ring_test notify_ring_test 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## 1. What is a ring queue 2 | -------------- 3 | 4 | * the data is "first in first out". 5 | * prev data of queue head is the queue tail. 6 | * the data of ring can reuse. 7 | 8 | 9 | ## 2. The advantages of ring queue 10 | -------------- 11 | 12 | * Guaranteed elements are first-in, first-out 13 | 14 | * Element space can be reused 15 | 16 | * Provides an efficient mechanism for multithread data transfer. 17 | 18 | 19 | ## 3. Ring queue of work example 20 | -------------- 21 | 22 | * Linux between kernel and system to transfor network data( PACKET_RX_RING and PACKET_TX_RING ) 23 | 24 | 25 | ## 4. Actual test results 26 | -------------- 27 | 28 | * In CentOS 5.5 (cpu per core frequency 1200MHz) . 29 | * ring queue length is 10000, one element data size is 4 bytes 30 | * [ring_test] the element writted and then to read is about 25 million per second. 31 | * [notify_ring_test] the element writted and then to read is about 20 million per second. 32 | -------------------------------------------------------------------------------- /doc/111.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dodng/fast_ring_queue/076dd66c4c51d418527a39839f2797e537e0bbfc/doc/111.jpg -------------------------------------------------------------------------------- /doc/2222.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dodng/fast_ring_queue/076dd66c4c51d418527a39839f2797e537e0bbfc/doc/2222.jpg -------------------------------------------------------------------------------- /doc/33333.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dodng/fast_ring_queue/076dd66c4c51d418527a39839f2797e537e0bbfc/doc/33333.jpg -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | /*from dodng 2 | 2016.12.9*/ 3 | #include 4 | #include "ring_queue.h" 5 | #include 6 | #include 7 | 8 | const int LOOP_SIZE = 10000; 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | 18 | #define THREAD_NUM 1 19 | 20 | #define DATA_TYPE int 21 | 22 | void *customer(void *arg) 23 | { 24 | Ring_Queue queue = *(Ring_Queue *)arg; 25 | 26 | while(1) 27 | { 28 | for(int i = 0;i < LOOP_SIZE; ) 29 | { 30 | int *p = 0; 31 | p = (DATA_TYPE *)queue.SOLO_Read(); 32 | if (p) 33 | { 34 | assert(i == *p); 35 | // printf("[%d]:%d\n",i,*p); 36 | queue.SOLO_Read_Over(); 37 | i++; 38 | } 39 | } 40 | } 41 | } 42 | 43 | void *producer(void *arg) 44 | { 45 | Ring_Queue queue = *(Ring_Queue *)arg; 46 | 47 | int loop = 0; 48 | struct timeval last_time,now_time; 49 | gettimeofday(&last_time,NULL); 50 | gettimeofday(&now_time,NULL); 51 | while(1) 52 | { 53 | for(int i = 0;i < LOOP_SIZE; ) 54 | { 55 | int *p = 0; 56 | p = (DATA_TYPE *)queue.SOLO_Write(); 57 | if (p) 58 | { 59 | *p = i; 60 | queue.SOLO_Write_Over(); 61 | i++; 62 | } 63 | } 64 | gettimeofday(&now_time,NULL); 65 | if (now_time.tv_sec - last_time.tv_sec >= 5) 66 | { 67 | printf("LOOP_COUNT is %.2f=[ %d[RING_SIZE] * %.2f[RING_COUNT]] per second\n",(LOOP_SIZE*loop)/5.0,LOOP_SIZE,loop/5.0); 68 | last_time = now_time; 69 | loop = 0; 70 | } 71 | loop++; 72 | } 73 | } 74 | 75 | int main(int argc,char *argv[]) 76 | { 77 | pthread_t tid_customer[THREAD_NUM]; 78 | pthread_t tid_producer[THREAD_NUM]; 79 | Ring_Queue *queue = new Ring_Queue[THREAD_NUM](LOOP_SIZE,sizeof(DATA_TYPE)); 80 | 81 | for (int i = 0; i < THREAD_NUM; i++) 82 | { 83 | if (pthread_create(&tid_customer[i],NULL,&customer,(void*)&queue[i]) != 0) 84 | { 85 | fprintf(stderr,"thread create failed\n"); 86 | return -1; 87 | } 88 | } 89 | for (int i = 0; i < THREAD_NUM; i++) 90 | { 91 | if (pthread_create(&tid_producer[i],NULL,&producer,(void*)&queue[i]) != 0) 92 | { 93 | fprintf(stderr,"thread create failed\n"); 94 | return -1; 95 | } 96 | } 97 | 98 | for (int i = 0 ;i < THREAD_NUM; i++) 99 | pthread_join(tid_customer[i],NULL); 100 | 101 | for (int i = 0 ;i < THREAD_NUM; i++) 102 | pthread_join(tid_producer[i],NULL); 103 | 104 | } 105 | -------------------------------------------------------------------------------- /notify_main.c: -------------------------------------------------------------------------------- 1 | /*from dodng 2 | 2016.12.9*/ 3 | #include 4 | #include "ring_queue.h" 5 | #include 6 | #include 7 | 8 | const int LOOP_SIZE = 10000; 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | 18 | #define THREAD_NUM 1 19 | 20 | #define DATA_TYPE int 21 | 22 | void *customer(void *arg) 23 | { 24 | Ring_Queue queue = *(Ring_Queue *)arg; 25 | u_char get_num = 0; 26 | while(1) 27 | { 28 | for(int i = 0;i < LOOP_SIZE; ) 29 | { 30 | int *p = 0; 31 | //begin--for notify 32 | recv(queue.notify_fd[1], &get_num, sizeof(get_num), 0); 33 | for(int j = 0 ; j < get_num;j++) 34 | //end----for notify 35 | { 36 | p = (DATA_TYPE *)queue.SOLO_Read(); 37 | if (p) 38 | { 39 | assert(i == *p); 40 | // printf("[%d]:%d\n",i,*p); 41 | queue.SOLO_Read_Over(); 42 | i++; 43 | } 44 | } 45 | } 46 | } 47 | } 48 | 49 | void *producer(void *arg) 50 | { 51 | Ring_Queue queue = *(Ring_Queue *)arg; 52 | 53 | int loop = 0; 54 | struct timeval last_time,now_time; 55 | gettimeofday(&last_time,NULL); 56 | gettimeofday(&now_time,NULL); 57 | u_char wrote_num = 0; 58 | while(1) 59 | { 60 | for(int i = 0;i < LOOP_SIZE; ) 61 | { 62 | int *p = 0; 63 | p = (DATA_TYPE *)queue.SOLO_Write(); 64 | if (p) 65 | { 66 | *p = i; 67 | queue.SOLO_Write_Over(); 68 | i++; 69 | //begin--for notify 70 | wrote_num++; 71 | if (wrote_num >= 200) 72 | { 73 | send(queue.notify_fd[0], &wrote_num, sizeof(wrote_num), MSG_NOSIGNAL); 74 | wrote_num = 0; 75 | } 76 | //end----for notify 77 | } 78 | } 79 | gettimeofday(&now_time,NULL); 80 | if (now_time.tv_sec - last_time.tv_sec >= 5) 81 | { 82 | printf("LOOP_COUNT is %.2f=[ %d[RING_SIZE] * %.2f[RING_COUNT]] per second\n",(LOOP_SIZE*loop)/5.0,LOOP_SIZE,loop/5.0); 83 | last_time = now_time; 84 | loop = 0; 85 | } 86 | loop++; 87 | } 88 | } 89 | 90 | int main(int argc,char *argv[]) 91 | { 92 | pthread_t tid_customer[THREAD_NUM]; 93 | pthread_t tid_producer[THREAD_NUM]; 94 | Ring_Queue *queue = new Ring_Queue[THREAD_NUM](LOOP_SIZE,sizeof(DATA_TYPE)); 95 | 96 | for (int i = 0; i < THREAD_NUM; i++) 97 | { 98 | if (pthread_create(&tid_customer[i],NULL,&customer,(void*)&queue[i]) != 0) 99 | { 100 | fprintf(stderr,"thread create failed\n"); 101 | return -1; 102 | } 103 | } 104 | for (int i = 0; i < THREAD_NUM; i++) 105 | { 106 | if (pthread_create(&tid_producer[i],NULL,&producer,(void*)&queue[i]) != 0) 107 | { 108 | fprintf(stderr,"thread create failed\n"); 109 | return -1; 110 | } 111 | } 112 | 113 | for (int i = 0 ;i < THREAD_NUM; i++) 114 | pthread_join(tid_customer[i],NULL); 115 | 116 | for (int i = 0 ;i < THREAD_NUM; i++) 117 | pthread_join(tid_producer[i],NULL); 118 | 119 | } 120 | -------------------------------------------------------------------------------- /ring_queue.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include /* See NOTES */ 4 | #include 5 | 6 | typedef unsigned char u_char; 7 | 8 | #define CAN_WRITE 0x00 9 | #define CAN_READ 0x01 10 | #define READING 0x02 11 | #define WRITING 0x03 12 | 13 | typedef struct tag 14 | { 15 | u_char tag_value; 16 | }TAG; 17 | 18 | 19 | class Ring_Queue 20 | { 21 | public: 22 | Ring_Queue(int nmemb,int size):_nmemb(nmemb),_size(size) 23 | ,_read_now(0),_write_now(0) 24 | { 25 | if ( nmemb <= 0 || size <=0 ) 26 | { 27 | assert(0); 28 | } 29 | _queue_p = NULL; 30 | _queue_p = new u_char[ nmemb * (sizeof(TAG) + size)]; 31 | memset(_queue_p,0,nmemb * (sizeof(TAG) + size)); 32 | 33 | socketpair(AF_UNIX, SOCK_SEQPACKET, 0, notify_fd); 34 | 35 | } 36 | ~Ring_Queue() 37 | { 38 | if (_queue_p) delete []_queue_p; 39 | 40 | } 41 | u_char * SOLO_Read() 42 | { 43 | u_char * g_p = 0; 44 | TAG * tag_p = 0; 45 | u_char *user_data = 0; 46 | 47 | g_p = queue_peek_nth(_queue_p,_read_now); 48 | tag_p = (TAG *)g_p; 49 | if (tag_p->tag_value == CAN_READ) 50 | { 51 | user_data = (u_char *)g_p + sizeof(TAG); 52 | tag_p->tag_value = READING; 53 | } 54 | return user_data; 55 | } 56 | void SOLO_Read_Over() 57 | { 58 | u_char * g_p = 0; 59 | TAG * tag_p = 0; 60 | 61 | g_p = queue_peek_nth(_queue_p,_read_now); 62 | tag_p = (TAG *)g_p; 63 | if (tag_p->tag_value == READING) 64 | { 65 | tag_p->tag_value = CAN_WRITE; 66 | _read_now = (_read_now + 1)% _nmemb; 67 | } 68 | } 69 | u_char * SOLO_Write() 70 | { 71 | u_char * g_p = 0; 72 | TAG * tag_p = 0; 73 | u_char *user_data = 0; 74 | 75 | g_p = queue_peek_nth(_queue_p,_write_now); 76 | tag_p = (TAG *)g_p; 77 | if (tag_p->tag_value == CAN_WRITE) 78 | { 79 | user_data = (u_char *)g_p + sizeof(TAG); 80 | tag_p->tag_value = WRITING; 81 | } 82 | return user_data; 83 | } 84 | void SOLO_Write_Over() 85 | { 86 | u_char * g_p = 0; 87 | TAG * tag_p = 0; 88 | 89 | g_p = queue_peek_nth(_queue_p,_write_now); 90 | tag_p = (TAG *)g_p; 91 | if (tag_p->tag_value == WRITING) 92 | { 93 | tag_p->tag_value = CAN_READ; 94 | _write_now = (_write_now + 1)% _nmemb; 95 | } 96 | } 97 | private: 98 | u_char *queue_peek_nth(u_char *queue_p,int pos) 99 | { 100 | u_char *rst = 0; 101 | if (queue_p && pos < _nmemb) 102 | { 103 | rst = queue_p + pos * (sizeof(TAG) + _size); 104 | } 105 | return rst; 106 | } 107 | u_char * _queue_p; 108 | int _nmemb; 109 | int _size; 110 | volatile int _read_now; 111 | volatile int _write_now; 112 | public: 113 | int notify_fd[2]; 114 | }; 115 | --------------------------------------------------------------------------------