C语言实现的可动态增长的队列

在基于事件或消息驱动的程序设计中,常常要用到队列这种数据结构。作者以此为背景,用C实现了一个Linux平台下的可动态增长的队列,并且可设置是否阻塞。只要将代码做简单的改变,就可以移植到其他平台上。

队列实现的并不完美,希望大家能不断修改,指正!

代码如下:

// Fifo.h ///


#ifndef  __CM_FIFO_H__
#define  __CM_FIFO_H__

#include "mutex.h"
#define bool int

struct MSGDATA
{
 void* data;
 struct MSGDATA* prev;
 struct MSGDATA* next;
};

typedef struct MSGDATA msgdata_t;

struct FIFO
{
 vmutex_t mutex;
 vcondition_t cond;
 
 msgdata_t* msg;
 msgdata_t *head;
 msgdata_t *tail; 
 
 int size;
 int elem_size;
 bool autosize;
 int discard;
 
};
typedef struct FIFO fifo_t;

void fifo_init(fifo_t *fifo, int s, int es, bool as);
int fifo_free(fifo_t *fifo);
int fifo_add(fifo_t *fifo, void* msg);
int fifo_get_next(fifo_t *fifo, void* msg);
int fifo_get_discard(fifo_t *fifo);


#endif

 

/// Fifo.c ///#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <sys/time.h>
#include <pthread.h>

#include "fifo.h"

static unsigned int max_size = 10;

static bool fwait(fifo_t *fifo, long millsec)
{

#if 0
 if (millsec < 0)
#endif

 return vcond_wait(&fifo->cond, &fifo->mutex);

 struct timeval now;
 struct timespec timeout;
 int retcode;
 gettimeofday(&now, NULL);
 timeout.tv_sec = now.tv_sec + 100000;
 timeout.tv_nsec = now.tv_usec * 1000 + millsec;
 
 retcode = vcond_timedwait(&fifo->cond, &fifo->mutex, &timeout);

 return 0;
  
}

static bool fwake_up(fifo_t *fifo)
{
 vcond_signal(&fifo->cond);
 return 0;
}


void fifo_init(fifo_t *fifo, int s, int es, bool as)
{
 assert(s > 0);
 assert(es > 0);
 assert(fifo != NULL);
 
 fifo->size = 0;
 fifo->elem_size = es;
 fifo->autosize = as;
 fifo->discard = 0;

 int i;
 msgdata_t* temp = NULL;

#ifdef FIFO_DEBUG
 char intbuf[256] = {0};
#endif
 
 for (i = 0; i < max_size; ++i)
 {
  msgdata_t* item = (msgdata_t*) malloc(sizeof(msgdata_t));
  item->data = malloc(fifo->elem_size);
  
#ifdef FIFO_DEBUG    
  sprintf(intbuf, "%x data-%d", item, i);
  memcpy(item->data, intbuf, strlen(intbuf));
#endif  
  
  if (i == 0)
  {
   item->prev = NULL;
   item->next = NULL;
   fifo->msg = item;
   temp = fifo->msg;
   fifo->head = fifo->tail = fifo->msg;
  }
  else
  {
   temp->next = item;
   item->prev = temp;
   item->next = NULL;
   temp = item;
  }
 }

 // Loop link
 temp->next = fifo->msg;
 fifo->msg->prev = temp;
 
 vmutex_init(&fifo->mutex);
 vcond_init(&fifo->cond);
 
}

int fifo_add(fifo_t *fifo, void* msg)
{
 // Queue is FULL
 if ((fifo->tail->next == fifo->head) || (fifo->head->prev == fifo->tail))
 {
  ++fifo->discard;
  
  if (!fifo->autosize)
  {
   #ifdef FIFO_DEBUG 
   printf("Queue is FULL, Discard the message!/n");
   #endif
   vmutex_unlock(&fifo->mutex);
   return -1;
  }

  // Resize this Queue
  msgdata_t* item = (msgdata_t*) malloc(sizeof(msgdata_t));
  item->data = malloc(fifo->elem_size);
  
  item->next = fifo->head;
  fifo->head->prev = item;

  fifo->tail->next = item;
  item->prev = fifo->tail;
  
 }

 // Add item to Queue
 memcpy(fifo->tail->data, msg, fifo->elem_size);
 //printf("Add==> %s, count = %d, new = %d/n", fifo->tail->data, fifo->size+1, fifo->discard);
 fifo->tail = fifo->tail->next;
 fifo->size++;

 fwake_up(fifo);
 vmutex_unlock(&fifo->mutex);
 return fifo->size;
 
}

int fifo_get_next(fifo_t *fifo, void* msg)
{
 assert(msg != NULL);

 // Block the thread when Queue is EMPTY
 
 vmutex_lock(&fifo->mutex);
 
 while (fifo->head == fifo->tail)
 {
  fwait(fifo, 10);
 }

 memcpy(msg, fifo->head->data, fifo->elem_size);
 fifo->head = fifo->head->next;
 fifo->size--;
 
 vmutex_unlock(&fifo->mutex);

 return fifo->size;

}

int fifo_get_discard(fifo_t *fifo)
{
 return fifo->discard;
}


int fifo_free(fifo_t *fifo)
{
 static int count = 0;
 msgdata_t* fprev,*fitem;
 fprev = fifo->msg->prev;
 fitem = fifo->msg->next;
 fprev->next = NULL;
#ifdef FIFO_DEBUG 
 printf("FREE item: %d - %s/n", count, (char*)fifo->msg->data);
#endif
 free(fifo->msg);
 fifo->msg = fitem;
 
 while (fifo->msg != NULL)
 {
  ++count;
  fitem = fifo->msg->next;
#ifdef FIFO_DEBUG   
  printf("Free item: %x, %d - %s/n", fifo->msg, count, (char*)fifo->msg->data);
#endif
  free(fifo->msg);
  fifo->msg = NULL;
  fifo->msg = fitem;
  
 }

 return count+1;
}

/// Mutex.h /


#ifndef  __CM_MUTEX_H__
#define  __CM_MUTEX_H__

#include <pthread.h>

typedef pthread_mutex_t     vmutex_t;
typedef pthread_cond_t  vcondition_t;

#define     vmutex_init(mutex) /
                pthread_mutex_init((mutex),0)
               

#define     vmutex_destroy(mutex) /
                pthread_mutex_destroy((mutex))
               

#define     vmutex_lock(mutex) /
                pthread_mutex_lock((mutex))


#define     vmutex_unlock(mutex) /
                pthread_mutex_unlock((mutex))


#define     vcond_init(cond) /
                pthread_cond_init((cond),0)
               

#define     vcond_destroy(cond) /
                pthread_cond_destroy((cond))
               

#define     vcond_wait(cond, mutex) /
                pthread_cond_wait((cond),(mutex))


#define     vcond_timedwait(cond, mutex, timeout) /
                pthread_cond_timedwait((cond),(mutex),(timeout))


#define     vcond_signal(cond) /
                pthread_cond_signal((cond))


#define     vcond_broadcast(cond) /
                pthread_cond_broadcast((cond))

#endif

 

/ Test_fifo.c ///

#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
#include "CMInterface.h"
#include "fifo.h"

fifo_t testfifo;
static int added1 = 0, added2 = 0;
static int readed = 0;
static int lock = 1;
void* thread_add1(void* p);
void* thread_add2(void* p);
void* thread_read(void* p);

int main()
{
 fifo_init(&testfifo, 10, 256, 1);
 
 pthread_t tadd1,tadd2,tread;
 
 pthread_create(&tread, NULL, thread_read, "Read");
 usleep(5);
 
 pthread_create(&tadd1, NULL, thread_add1, "Add1");
 //pthread_create(&tadd2, NULL, thread_add2, "Add2");

 pthread_join(tread, NULL);

 return 0;
}


void* thread_add1(void* p)
{
 char* name = (char*)(p);
 printf("Thread %s Starting.../n", name);
 int count = 0;

 for (;;)
 {
  char buffer[256] = {0};
  sprintf(buffer, "Event %d From %s", ++count, name);
  fifo_add(&testfifo, buffer);
  ++added1;
  if (added1 == 1000) break;
  if (added1 % 50 == 0)
   usleep(1);

 }
 
 printf("add = %d, discard = %d, vaild = %d/n", count, fifo_get_discard(&testfifo), count - fifo_get_discard(&testfifo));

 return p;
}

void* thread_add2(void* p)
{
 char* name = (char*)(p);
 printf("Thread %s Starting.../n", name);
 int count = 0;
 
 for (;;)
 {
  char buffer[256] = {0};
  sprintf(buffer, "Event %d From %s", ++count, name);
  
  if (-1 != fifo_add(&testfifo, buffer))
  {
   ++added2;
   printf("Add2==> %s/n", buffer);
   if (added2 == 1000) break;

   if (added2 % 10 == 0)
    usleep(1);
  }
  
 }

 return p;
}

void* thread_read(void* p)
{
 char* name = (char*)(p);
 printf("Thread %s Starting.../n", name);
 int count = 0;
 
 while(lock)
 {
  char buffer[256] = {0};
  count = fifo_get_next(&testfifo,buffer);
  
  if (1)
  {
   ++readed;
   printf("Get<=== %s/tcount = %d, discard = %d/n", buffer, readed, fifo_get_discard(&testfifo));
  }

  if (readed >= 1000)
  {
   printf("Break/n");
   break;
  }
 }

 printf("Get here/n");

 int free_items = fifo_free(&testfifo);
 printf("/r/n######## Free itemS: %d/n", free_items);

 return p;
}

 

// Makefile.post //

all : $(target)

OBJS = $(SRCS:.c=.o)
SOBJS = $(SSRCS:.c=.o)

%.o : %.c
 $(CC) $(C_FLAGS) $(INC_DIR) $?

$(target) : $(OBJS)
 $(CC) $(LD_FLAGS) $@ $(OBJS) $(LD_PATH) $(LD_LIBS)


clean:
 rm -rf *.o $(target)

// Makefile.prev ///

CC = gcc
C_FLAGS = -Wall -O2 -c
LD_FLAGS = -rdynamic -s -o
LD_LIBS =
LD_PATH =
SLD_FLAGS = -shared -o

INC_DIR = -I$(TOP_DIR)/include

MKDIR = mkdir -p
MV = mv
CP = cp -rf

 

/ Makefile for Fifo //

TOP_DIR = $(shell pwd)..
include ../Makefile.prev
LD_FLAGS = $(SLD_FLAGS)
C_FLAGS += -DFIFO_DEBUG
target :=  libutils.so

SRCS = fifo.c

include ../Makefile.post

Makefile for Test //

TOPDIR = $(shell pwd)

SUBDIRS += test_fifo ipcserver ipcclient

all:
 $(foreach dir,$(SUBDIRS), cd $(dir) && $(MAKE) && cd $(TOPDIR); )
 
print:
 $(foreach dir,$(SUBDIRS), cd $(dir) && $(MAKE) print && cd $(TOPDIR); )
 
clean:
 $(foreach dir,$(SUBDIRS), cd $(dir) && $(MAKE) clean && cd $(TOPDIR); )

///

TOP_DIR = $(shell pwd)/..
include ../Makefile.prev
LD_LIBS = -ldl -lpthread -lutils
LD_PATH = -L../utils
INC_DIR += -I$(TOP_DIR)/utils
target :=  testfifo

SRCS = test_fifo.c

include ../Makefile.post

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值