1. cam_list
#define member_of(ptr, type, member) ({ const typeof(((type *)0)->member) *__mptr = (ptr); (type *)((char *)__mptr - offsetof(type,member));}) struct cam_list { struct cam_list *next, *prev; }; static inline void cam_list_init(struct cam_list *ptr) { ptr->next = ptr; ptr->prev = ptr; } static inline void cam_list_add_tail_node(struct cam_list *item, struct cam_list *head) { struct cam_list *prev = head->prev; head->prev = item; item->next = head; item->prev = prev; prev->next = item; } static inline void cam_list_insert_before_node(struct cam_list *item, struct cam_list *node) { item->next = node; item->prev = node->prev; item->prev->next = item; node->prev = item; } static inline void cam_list_del_node(struct cam_list *ptr) { struct cam_list *prev = ptr->prev; struct cam_list *next = ptr->next; next->prev = ptr->prev; prev->next = ptr->next; ptr->next = ptr; ptr->prev = ptr; }
链表就不说了,和内核链表的实现思想一致。
2. cam_queue
为什么定义 queue?
目的就是多线程使用,可以一个线程不断的读 queue ,其他线程不断的写 queue,这样可以实现事件的统一分发处理。常用机制。
#include "cam_list.h" typedef struct { struct cam_list list; // 用链表管理 queue 的结点 void *data; } cam_node_t; // 定义 queue 的结点 typedef struct { cam_node_t head; /* dummy head */ uint32_t size; pthread_mutex_t lock; } cam_queue_t; static inline int32_t cam_queue_init(cam_queue_t *queue) // 初始化 { pthread_mutex_init(&queue->lock, NULL); cam_list_init(&queue->head.list); queue->size = 0; return 0; } static inline int32_t cam_queue_enq(cam_queue_t *queue, void *data) // 入队 { cam_node_t *node = (cam_node_t *)malloc(sizeof(cam_node_t)); if (NULL == node) { return -1; } memset(node, 0, sizeof(cam_node_t)); node->data = data; pthread_mutex_lock(&queue->lock); // 天生为多线程存在,竞争资源必须加锁 cam_list_add_tail_node(&node->list, &queue->head.list); queue->size++; pthread_mutex_unlock(&queue->lock); return 0; } static inline void *cam_queue_deq(cam_queue_t *queue) // 出队 { cam_node_t *node = NULL; void *data = NULL; struct cam_list *head = NULL; struct cam_list *pos = NULL; pthread_mutex_lock(&queue->lock); head = &queue->head.list; pos = head->next; if (pos != head) { // 内部链表不为空,获取链表头结点 node = member_of(pos, cam_node_t, list); cam_list_del_node(&node->list); queue->size--; } pthread_mutex_unlock(&queue->lock); if (NULL != node) { // 将 结点 内存释放,将用户内存指针返回 data = node->data; free(node); } return data; } static inline int32_t cam_queue_flush(cam_queue_t *queue) // 清空 queue。即遍历删除所有的 queue 结点,然后释放 结点 内存。 { cam_node_t *node = NULL; struct cam_list *head = NULL; struct cam_list *pos = NULL; pthread_mutex_lock(&queue->lock); head = &queue->head.list; pos = head->next; while(pos != head) { node = member_of(pos, cam_node_t, list); pos = pos->next; cam_list_del_node(&node->list); queue->size--; /* TODO later to consider ptr inside data */ /* for now we only assume there is no ptr inside data * so we free data directly */ if (NULL != node->data) { free(node->data); } free(node); } queue->size = 0; pthread_mutex_unlock(&queue->lock); return 0; } static inline int32_t cam_queue_deinit(cam_queue_t *queue) { cam_queue_flush(queue); pthread_mutex_destroy(&queue->lock); return 0; }
优点:
操作灵活,数据区域完全由用户自己定义。给用户的足够的操作空间。
缺点:
在多线程操作中,如果没有事件处理,就是 queue 为空时,必然要等待。以前我都会将等待做到队列里,由用户指定等待时间。