[C]无锁循环队列

/*
 * 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

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 tail
int 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 head
int 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 tail
int 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 head
int 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
#include
#include
#include


#define QUEUE_SIZE	100
#define THREAD_NUM	100
#define LOOP_NUM	1000000

lfrq_queue_t *q;

long long total=1;

void* producer(void*p)
{
	long long *d;
	int i;
	for(i=0;i




你可能感兴趣的:(c/c++)