[C]无锁循环队列
来源:互联网 发布:海盐行知中学 编辑:程序博客网 时间:2024/05/16 06:36
/* * lock free ring queue, thread safe * this paper "A practical nonblocking queue algorithm using compare-and-swap" provide the main idea * lfrq_queue.h * enqueue into the tail * dequeue from head */#ifndef __LOCK_FREE_RING_QUEUE_H__#define __LOCK_FREE_RING_QUEUE_H__typedef int int_t;typedef long long int_2t;#define sync_get_2t(val_ptr)__sync_fetch_and_add((val_ptr),0)#define sync_inc_t(val_ptr)__sync_fetch_and_add((val_ptr),1)#define sync_dec_t(val_ptr)__sync_fetch_and_sub((val_ptr),1)#define sync_cas_2t(val_ptr,old_val,new_val)__sync_bool_compare_and_swap((val_ptr),(old_val),(new_val))#define int_2t_low_part_ptr(x)((int_t*)(&(x)))#define int_2t_high_part_ptr(x)(((int_t*)(&(x)))+1)#define int_2t_low_part(x)(*(int_2t_low_part_ptr(x)))#define int_2t_high_part(x)(*(int_2t_high_part_ptr(x)))typedef struct{void *m_data_queue;int_2t *m_free_array;int_2t *m_data_array;int_2t m_free_head;int_2t m_free_tail;int_2t m_data_head;int_2t m_data_tail;int_t m_capacity;int_t m_type_size;int_t m_type_num;}lfrq_queue_t;lfrq_queue_t* lfrq_queue_create(const int_t type_number,const int_t type_size);void lfrq_queue_free(lfrq_queue_t *p);int lfrq_queue_enqueue_free(lfrq_queue_t *f, const void*p); //if success, reurn 0, else return -1;int lfrq_queue_dequeue_free(lfrq_queue_t *f, void**p); //if success, reurn 0, else return -1;int lfrq_queue_enqueue_data(lfrq_queue_t *f, const void*p); //if success, reurn 0, else return -1;int lfrq_queue_dequeue_data(lfrq_queue_t *f, void**p); //if success, reurn 0, else return -1;const int_t lfrq_size(lfrq_queue_t *f);#endif
====================================
/* * lock free ring queue, thread safe * lfrq_queue.c */#include"lfrq_queue.h"#include<stdlib.h>lfrq_queue_t* lfrq_queue_create(const int_t type_number,const int_t type_size){int i;if(type_number<1) return NULL;lfrq_queue_t *p=(lfrq_queue_t*)malloc(sizeof(lfrq_queue_t));if(p==NULL) return NULL;p->m_capacity=type_number+1;p->m_type_size = type_size;p->m_data_queue =(void*)calloc(type_number,type_size);if(p->m_data_queue==NULL){free(p);return NULL;}p->m_free_array =(int_2t*)calloc(p->m_capacity,sizeof(int_2t));if(p->m_free_array==NULL){free(p->m_data_queue);free(p);return NULL;}p->m_data_array =(int_2t*)calloc(p->m_capacity,sizeof(int_2t));if(p->m_data_array==NULL){free(p->m_free_array);free(p->m_data_array);free(p);return NULL;}int_2t_low_part(p->m_free_tail)=p->m_capacity-1;int_2t_high_part(p->m_free_tail)=0;p->m_free_head=0;p->m_data_head=0;p->m_data_tail=0;p->m_type_num=0;for(i=0; i < p->m_capacity; ++i){int_2t_low_part(p->m_free_array[i])=i;int_2t_high_part(p->m_free_array[i])=0;int_2t_low_part(p->m_data_array[i])=-1;int_2t_high_part(p->m_data_array[i])=0;}int_2t_low_part(p->m_free_array[p->m_capacity-1])=-1;return p;}void lfrq_queue_free(lfrq_queue_t *p){if(p->m_capacity>1){free(p->m_data_array);free(p->m_free_array);free(p->m_data_array);free(p);}}//enqueue one free node back to the tailint lfrq_queue_enqueue_free(lfrq_queue_t *f, const void*p){int_t index = (p - f->m_data_queue)/(f->m_type_size);for(;;){int_2t tail = sync_get_2t(&(f->m_free_tail));int_2t head = sync_get_2t(&(f->m_free_head));int_t tail_ptr = int_2t_low_part(tail);int_t head_ptr = int_2t_low_part(head);int_t tail_next_ptr = tail_ptr+1;if(tail_next_ptr==f->m_capacity) tail_next_ptr=0;if(tail!=sync_get_2t(&(f->m_free_tail))) continue;if(tail_next_ptr==head_ptr) return -1;int_2t tail_ptr_old_val = sync_get_2t(&(f->m_free_array[tail_ptr]));int_t tail_ptr_old_val_ptr = int_2t_low_part(tail_ptr_old_val);if(tail_ptr_old_val_ptr==-1){int_2t tail_ptr_new_val = tail_ptr_old_val;int_2t_low_part(tail_ptr_new_val) = index;int_2t_high_part(tail_ptr_new_val) = int_2t_high_part(tail_ptr_old_val)+1;if(sync_cas_2t(&(f->m_free_array[tail_ptr]),tail_ptr_old_val,tail_ptr_new_val)){int_2t tail_new = tail;int_2t_low_part(tail_new)=tail_next_ptr;int_2t_high_part(tail_new)=int_2t_high_part(tail)+1;sync_cas_2t(&(f->m_free_tail),tail,tail_new);return 0;}}else{int_2t tail_new = tail;int_2t_low_part(tail_new)=tail_next_ptr;int_2t_high_part(tail_new)=int_2t_high_part(tail)+1;sync_cas_2t(&(f->m_free_tail),tail,tail_new);}}}//dequeue one free node from the headint lfrq_queue_dequeue_free(lfrq_queue_t *f, void**p){for(;;){int_2t head = sync_get_2t(&(f->m_free_head));int_2t tail = sync_get_2t(&(f->m_free_tail));int_t head_ptr = int_2t_low_part(head);int_t tail_ptr = int_2t_low_part(tail);if(head!=sync_get_2t(&(f->m_free_head))) continue;if(head_ptr==tail_ptr) return -1;int_2t head_ptr_old_val = sync_get_2t(&(f->m_free_array[head_ptr]));int_t head_ptr_old_val_ptr = int_2t_low_part(head_ptr_old_val);if(head_ptr_old_val_ptr!=-1){int_2t head_ptr_new_val = head_ptr_old_val;int_2t_low_part(head_ptr_new_val)=-1;int_2t_high_part(head_ptr_new_val)=int_2t_high_part(head_ptr_old_val)+1;if(sync_cas_2t(&(f->m_free_array[head_ptr]),head_ptr_old_val,head_ptr_new_val)){int_2t head_new = head;int_t head_new_ptr = int_2t_low_part(head_new)+1;if(head_new_ptr==f->m_capacity) head_new_ptr=0;int_2t_low_part(head_new)=head_new_ptr;int_2t_high_part(head_new)=int_2t_high_part(head)+1;sync_cas_2t(&(f->m_free_head),head,head_new);*p=head_ptr_old_val_ptr*f->m_type_size + f->m_data_queue;return 0;}}else{int_2t head_new = head;int_t head_new_ptr = int_2t_low_part(head_new)+1;if(head_new_ptr==f->m_capacity) head_new_ptr=0;int_2t_low_part(head_new)=head_new_ptr;int_2t_high_part(head_new)=int_2t_high_part(head)+1;sync_cas_2t(&(f->m_free_head),head,head_new);}}}//enqueue one data node back to the tailint lfrq_queue_enqueue_data(lfrq_queue_t *f, const void*p){int_t index = (p - f->m_data_queue)/(f->m_type_size);for(;;){int_2t tail = sync_get_2t(&(f->m_data_tail));int_2t head = sync_get_2t(&(f->m_data_head));int_t tail_ptr = int_2t_low_part(tail);int_t head_ptr = int_2t_low_part(head);int_t tail_next_ptr = tail_ptr+1;if(tail_next_ptr==f->m_capacity) tail_next_ptr=0;if(tail!=sync_get_2t(&(f->m_data_tail))) continue;if(tail_next_ptr==head_ptr) return -1;int_2t tail_ptr_old_val = sync_get_2t(&(f->m_data_array[tail_ptr]));int_t tail_ptr_old_val_ptr = int_2t_low_part(tail_ptr_old_val);if(tail_ptr_old_val_ptr==-1){int_2t tail_ptr_new_val = tail_ptr_old_val;int_2t_low_part(tail_ptr_new_val) = index;int_2t_high_part(tail_ptr_new_val) = int_2t_high_part(tail_ptr_old_val)+1;if(sync_cas_2t(&(f->m_data_array[tail_ptr]),tail_ptr_old_val,tail_ptr_new_val)){int_2t tail_new = tail;int_2t_low_part(tail_new)=tail_next_ptr;int_2t_high_part(tail_new)=int_2t_high_part(tail)+1;sync_cas_2t(&(f->m_data_tail),tail,tail_new);sync_inc_t(&(f->m_type_num));return 0;}}else{int_2t tail_new = tail;int_2t_low_part(tail_new)=tail_next_ptr;int_2t_high_part(tail_new)=int_2t_high_part(tail)+1;sync_cas_2t(&(f->m_data_tail),tail,tail_new);}}}//dequeue one data node from the headint lfrq_queue_dequeue_data(lfrq_queue_t *f, void**p){for(;;){int_2t head = sync_get_2t(&(f->m_data_head));int_2t tail = sync_get_2t(&(f->m_data_tail));int_t head_ptr = int_2t_low_part(head);int_t tail_ptr = int_2t_low_part(tail);if(head!=sync_get_2t(&(f->m_data_head))) continue;if(head_ptr==tail_ptr) return -1;int_2t head_ptr_old_val = sync_get_2t(&(f->m_data_array[head_ptr]));int_t head_ptr_old_val_ptr = int_2t_low_part(head_ptr_old_val);if(head_ptr_old_val_ptr!=-1){int_2t head_ptr_new_val = head_ptr_old_val;int_2t_low_part(head_ptr_new_val)=-1;int_2t_high_part(head_ptr_new_val)=int_2t_high_part(head_ptr_old_val)+1;if(sync_cas_2t(&(f->m_data_array[head_ptr]),head_ptr_old_val,head_ptr_new_val)){int_2t head_new = head;int_t head_new_ptr = int_2t_low_part(head_new)+1;if(head_new_ptr==f->m_capacity) head_new_ptr=0;int_2t_low_part(head_new)=head_new_ptr;int_2t_high_part(head_new)=int_2t_high_part(head)+1;sync_cas_2t(&(f->m_data_head),head,head_new);*p=head_ptr_old_val_ptr*f->m_type_size + f->m_data_queue;sync_dec_t(&(f->m_type_num));return 0;}}else{int_2t head_new = head;int_t head_new_ptr = int_2t_low_part(head_new)+1;if(head_new_ptr==f->m_capacity) head_new_ptr=0;int_2t_low_part(head_new)=head_new_ptr;int_2t_high_part(head_new)=int_2t_high_part(head)+1;sync_cas_2t(&(f->m_data_head),head,head_new);}}}const int_t lfrq_size(lfrq_queue_t *f){ return f->m_type_num; }======================
测试程序
#include"lfrq_queue.h"#include<stdio.h>#include<stdlib.h>#include<unistd.h>#include<pthread.h>#define QUEUE_SIZE100#define THREAD_NUM100#define LOOP_NUM1000000lfrq_queue_t *q;long long total=1;void* producer(void*p){long long *d;int i;for(i=0;i<LOOP_NUM;++i){while(lfrq_queue_dequeue_free(q,(void**)&d));*d=__sync_fetch_and_add(&total,1);while(lfrq_queue_enqueue_data(q,(void*)d));}}void* consumer(void*p){long long*d;long long*cnt=(long long*)p;int i;for(i=0;i<LOOP_NUM;++i){while(lfrq_queue_dequeue_data(q,(void**)&d));*cnt += *d;while(lfrq_queue_enqueue_free(q,(void*)d));}}int main(){pthread_t threads[THREAD_NUM*2];long long cnt[THREAD_NUM];long long sum=0;long long expect=THREAD_NUM*LOOP_NUM;int i;q=lfrq_queue_create(QUEUE_SIZE,sizeof(long long));if(q==NULL){printf("create lfrq error\n");return 0;}for(i=0;i<THREAD_NUM;++i) cnt[i]=0;for(i=0;i<THREAD_NUM;++i){if(pthread_create(threads+i,NULL,producer,NULL)){printf("Error at create thread %d\n",i);}}for(i=0;i<THREAD_NUM;++i){if(pthread_create(threads+i+THREAD_NUM,NULL,consumer,cnt+i)){printf("Error at create thread %d\n",i+THREAD_NUM);}}for(i=0;i<THREAD_NUM*2;++i){if(pthread_join(threads[i],NULL)){printf("Error at join thread %d\n",i);}}for(i=0;i<THREAD_NUM;++i){sum+=cnt[i];printf("%d=%lld\n",i,cnt[i]);}printf("Actual Value : %lld\n",sum);expect=(expect*(expect+1))/2;printf("Expect Value : %lld\n",expect);return 0;}
0 0
- [C]无锁循环队列
- [c++]无锁队列
- 无锁队列的实现-循环数组
- LinuxC一站式编程.循环队列无锁实现
- 单生产者单消费者循环无锁队列
- 一次无锁循环队列的编写回顾
- c循环队列
- C的循环队列
- 循环队列实现(C++)
- C语言循环队列
- C基础:循环队列
- 循环队列(C语言版)
- C循环队列
- C-循环队列
- C 循环队列实现
- 循环队列(c)
- c语言:循环队列
- 循环队列 - C语言
- Codeforces Round #321 (Div. 2)C. Kefa and Park
- C#windfrom控件之datagridview(一)
- js-回调函数
- POJ 3916:Duplicate Removal 将相近的重复元素删除
- Ubuntu 14.10下部署Django到Apache服务器
- [C]无锁循环队列
- D-S证据理论学习笔记(二)
- 协议的类型限制
- java篇 【7】方法(函数)的声明及使用
- c#学习日记01--新手上路
- 基于ImageView的多点触控,双击放大缩小以及结合ViewPager的事件冲突
- SDWebImage框架,清除图片
- 联萌十一大决战之强力热身 A. Easy Math
- 《构建之法》第十五章 稳定和发布阶段