linux下C语言实现多线程通信—环形缓冲区,可用于生产者(producer)/消费者(consumer)【转】
转自:http://blog.chinaunix.net/uid-28458801-id-4262445.html
操作系统:ubuntu10.04
前言:
在嵌入式开发中,只要是带操作系统的,在其上开发产品应用,基本都需要用到多线程。
为了提高效率,尽可能的提高并发率。因此,线程之间的通信就是问题的核心。
根据当前产品需要,使用 环形缓冲区 解决。
一,环形缓冲区的实现
1,cbuf.h
点击(此处)折叠或打开
- #ifndef __CBUF_H__
- #define __CBUF_H__
- #ifdef __cplusplus
- extern "C" {
- #endif
- /* Define to prevent recursive inclusion
- -------------------------------------*/
- #include "types.h"
- #include "thread.h"
- typedef struct _cbuf
- {
- int32_t size; /* 当前缓冲区中存放的数据的个数 */
- int32_t next_in; /* 缓冲区中下一个保存数据的位置 */
- int32_t next_out; /* 从缓冲区中取出下一个数据的位置 */
- int32_t capacity; /* 这个缓冲区的可保存的数据的总个数 */
- mutex_t mutex; /* Lock the structure */
- cond_t not_full; /* Full -> not full condition */
- cond_t not_empty; /* Empty -> not empty condition */
- void *data[CBUF_MAX];/* 缓冲区中保存的数据指针 */
- }cbuf_t;
- /* 初始化环形缓冲区 */
- extern int32_t cbuf_init(cbuf_t *c);
- /* 销毁环形缓冲区 */
- extern void cbuf_destroy(cbuf_t *c);
- /* 压入数据 */
- extern int32_t cbuf_enqueue(cbuf_t *c,void *data);
- /* 取出数据 */
- extern void* cbuf_dequeue(cbuf_t *c);
- /* 判断缓冲区是否为满 */
- extern bool cbuf_full(cbuf_t *c);
- /* 判断缓冲区是否为空 */
- extern bool cbuf_empty(cbuf_t *c);
- /* 获取缓冲区可存放的元素的总个数 */
- extern int32_t cbuf_capacity(cbuf_t *c);
- #ifdef __cplusplus
- }
- #endif
- #endif
- /* END OF FILE
- ---------------------------------------------------------------*/
2,cbuf.c
点击(此处)折叠或打开
- #include "cbuf.h"
- /* 初始化环形缓冲区 */
- int32_t cbuf_init(cbuf_t *c)
- {
- int32_t ret = OPER_OK;
- if((ret = mutex_init(&c->mutex)) != OPER_OK)
- {
- #ifdef DEBUG_CBUF
- debug("cbuf init fail ! mutex init fail !\n");
- #endif
- return ret;
- }
- if((ret = cond_init(&c->not_full)) != OPER_OK)
- {
- #ifdef DEBUG_CBUF
- debug("cbuf init fail ! cond not full init fail !\n");
- #endif
- mutex_destroy(&c->mutex);
- return ret;
- }
- if((ret = cond_init(&c->not_empty)) != OPER_OK)
- {
- #ifdef DEBUG_CBUF
- debug("cbuf init fail ! cond not empty init fail !\n");
- #endif
- cond_destroy(&c->not_full);
- mutex_destroy(&c->mutex);
- return ret;
- }
- c->size = 0;
- c->next_in = 0;
- c->next_out = 0;
- c->capacity = CBUF_MAX;
- #ifdef DEBUG_CBUF
- debug("cbuf init success !\n");
- #endif
- return ret;
- }
- /* 销毁环形缓冲区 */
- void cbuf_destroy(cbuf_t *c)
- {
- cond_destroy(&c->not_empty);
- cond_destroy(&c->not_full);
- mutex_destroy(&c->mutex);
- #ifdef DEBUG_CBUF
- debug("cbuf destroy success \n");
- #endif
- }
- /* 压入数据 */
- int32_t cbuf_enqueue(cbuf_t *c,void *data)
- {
- int32_t ret = OPER_OK;
- if((ret = mutex_lock(&c->mutex)) != OPER_OK) return ret;
- /*
- * Wait while the buffer is full.
- */
- while(cbuf_full(c))
- {
- #ifdef DEBUG_CBUF
- debug("cbuf is full !!!\n");
- #endif
- cond_wait(&c->not_full,&c->mutex);
- }
- c->data[c->next_in++] = data;
- c->size++;
- c->next_in %= c->capacity;
- mutex_unlock(&c->mutex);
- /*
- * Let a waiting consumer know there is data.
- */
- cond_signal(&c->not_empty);
- #ifdef DEBUG_CBUF
- // debug("cbuf enqueue success ,data : %p\n",data);
- debug("enqueue\n");
- #endif
- return ret;
- }
- /* 取出数据 */
- void* cbuf_dequeue(cbuf_t *c)
- {
- void *data = NULL;
- int32_t ret = OPER_OK;
- if((ret = mutex_lock(&c->mutex)) != OPER_OK) return NULL;
- /*
- * Wait while there is nothing in the buffer
- */
- while(cbuf_empty(c))
- {
- #ifdef DEBUG_CBUF
- debug("cbuf is empty!!!\n");
- #endif
- cond_wait(&c->not_empty,&c->mutex);
- }
- data = c->data[c->next_out++];
- c->size--;
- c->next_out %= c->capacity;
- mutex_unlock(&c->mutex);
- /*
- * Let a waiting producer know there is room.
- * 取出了一个元素,又有空间来保存接下来需要存储的元素
- */
- cond_signal(&c->not_full);
- #ifdef DEBUG_CBUF
- // debug("cbuf dequeue success ,data : %p\n",data);
- debug("dequeue\n");
- #endif
- return data;
- }
- /* 判断缓冲区是否为满 */
- bool cbuf_full(cbuf_t *c)
- {
- return (c->size == c->capacity);
- }
- /* 判断缓冲区是否为空 */
- bool cbuf_empty(cbuf_t *c)
- {
- return (c->size == 0);
- }
- /* 获取缓冲区可存放的元素的总个数 */
- int32_t cbuf_capacity(cbuf_t *c)
- {
- return c->capacity;
- }
二,辅助文件
为了提高程序的移植性,对线程相关进行封装。
1,thread.h
点击(此处)折叠或打开
- #ifndef __THREAD_H__
- #define __THREAD_H__
- #ifdef __cplusplus
- extern "C" {
- #endif
- /* Define to prevent recursive inclusion
- -------------------------------------*/
- #include "types.h"
- typedef struct _mutex
- {
- pthread_mutex_t mutex;
- }mutex_t;
- typedef struct _cond
- {
- pthread_cond_t cond;
- }cond_t;
- typedef pthread_t tid_t;
- typedef pthread_attr_t attr_t;
- typedef void* (* thread_fun_t)(void*);
- typedef struct _thread
- {
- tid_t tid;
- cond_t *cv;
- int32_t state;
- int32_t stack_size;
- attr_t attr;
- thread_fun_t fun;
- }thread_t;
- /* mutex */
- extern int32_t mutex_init(mutex_t *m);
- extern int32_t mutex_destroy(mutex_t *m);
- extern int32_t mutex_lock(mutex_t *m);
- extern int32_t mutex_unlock(mutex_t *m);
- /* cond */
- extern int32_t cond_init(cond_t *c);
- extern int32_t cond_destroy(cond_t *c);
- extern int32_t cond_signal(cond_t *c);
- extern int32_t cond_wait(cond_t *c,mutex_t *m);
- /* thread */
- /* 线程的创建,其属性的设置等都封装在里面 */
- extern int32_t thread_create(thread_t *t);
- //extern int32_t thread_init(thread_t *t);
- #define thread_join(t, p) pthread_join(t, p)
- #define thread_self() pthread_self()
- #define thread_sigmask pthread_sigmask
- #ifdef __cplusplus
- }
- #endif
- #endif
- /* END OF FILE
- ---------------------------------------------------------------*/
2,thread.c
点击(此处)折叠或打开
- #include "thread.h"
- /* mutex */
- int32_t mutex_init(mutex_t *m)
- {
- int32_t ret = OPER_OK;
- if((ret = pthread_mutex_init(&m->mutex, NULL)) != 0)
- ret = -THREAD_MUTEX_INIT_ERROR;
- return ret;
- }
- int32_t mutex_destroy(mutex_t *m)
- {
- int32_t ret = OPER_OK;
- if((ret = pthread_mutex_destroy(&m->mutex)) != 0)
- ret = -MUTEX_DESTROY_ERROR;
- return ret;
- }
- int32_t mutex_lock(mutex_t *m)
- {
- int32_t ret = OPER_OK;
- if((ret = pthread_mutex_lock(&m->mutex)) != 0)
- ret = -THREAD_MUTEX_LOCK_ERROR;
- return ret;
- }
- int32_t mutex_unlock(mutex_t *m)
- {
- int32_t ret = OPER_OK;
- if((ret = pthread_mutex_unlock(&m->mutex)) != 0)
- ret = -THREAD_MUTEX_UNLOCK_ERROR;
- return ret;
- }
- /* cond */
- int32_t cond_init(cond_t *c)
- {
- int32_t ret = OPER_OK;
- if((ret = pthread_cond_init(&c->cond, NULL)) != 0)
- ret = -THREAD_COND_INIT_ERROR;
- return ret;
- }
- int32_t cond_destroy(cond_t *c)
- {
- int32_t ret = OPER_OK;
- if((ret = pthread_cond_destroy(&c->cond)) != 0)
- ret = -COND_DESTROY_ERROR;
- return ret;
- }
- int32_t cond_signal(cond_t *c)
- {
- int32_t ret = OPER_OK;
- if((ret = pthread_cond_signal(&c->cond)) != 0)
- ret = -COND_SIGNAL_ERROR;
- return ret;
- }
- int32_t cond_wait(cond_t *c,mutex_t *m)
- {
- int32_t ret = OPER_OK;
- if((ret = pthread_cond_wait(&c->cond, &m->mutex)) != 0)
- ret = -COND_WAIT_ERROR;
- return ret;
- }
三,测试
1,测试代码
点击(此处)折叠或打开
- /*
- * cbuf begin
- */
- #define OVER (-1)
- static cbuf_t cmd;
- static int line_1[200];
- static int line_2[200];
- //static int temp = 0;
- static bool line1_finish = false;
- static bool line2_finish = false;
- void* producer_1(void *data)
- {
- int32_t i = 0;
- for(i = 0; i < 200; i++)
- {
- line_1[i] = i+1000;
- cbuf_enqueue(&cmd, &line_1[i]);
- if(0 == (i % 9)) sleep(1);
- }
- line1_finish = true;
- return NULL;
- }
- void* producer_2(void *data)
- {
- int32_t i = 0;
- for(i = 0; i < 200; i++)
- {
- line_2[i] = i+20000;
- cbuf_enqueue(&cmd, &line_2[i]);
- if(0 == (i % 9)) sleep(1);
- }
- line2_finish = true;
- return NULL;
- }
- void* consumer(void *data)
- {
- int32_t *ptr = NULL;
- while(1)
- {
- ptr = cbuf_dequeue(&cmd);
- printf("%d\n",*ptr);
- if(cbuf_empty(&cmd) && line2_finish && line1_finish)
- {
- printf("quit\n");
- break;
- }
- }
- return NULL;
- }
- void test_cbuf_oper(void)
- {
- pthread_t l_1;
- pthread_t l_2;
- pthread_t c;
- cbuf_init(&cmd);
- pthread_create(&l_1,NULL,producer_1,0);
- pthread_create(&l_2,NULL,producer_2,0);
- pthread_create(&c,NULL,consumer,0);
- pthread_join(l_1,NULL);
- pthread_join(l_2,NULL);
- pthread_join(c,NULL);
- cbuf_destroy(&cmd);
- }
- void test_cbuf(void)
- {
- test_cbuf_oper();
- }
- /*
- * cbuf end
- */
2,测试结果
四,参考文件
1,《bareos-master》源码
2,《nginx》源码
linux下C语言实现多线程通信—环形缓冲区,可用于生产者(producer)/消费者(consumer)【转】的更多相关文章
- linux下c语言的多线程编程
我们在写linux的服务的时候,经常会用到linux的多线程技术以提高程序性能 多线程的一些小知识: 一个应用程序可以启动若干个线程. 线程(Lightweight Process,LWP),是程序执 ...
- linux下c语言实现多线程文件复制【转】
转自:https://www.cnblogs.com/zxl0715/articles/5365989.html .具体思路 把一个文件分成N份,分别用N个线程copy, 每个线程只读取指定长度字节大 ...
- Linux下c语言TCP多线程聊天室
开发环境:Linux,GCC 相关知识:TCP(博客:传送门),线程 附加:项目可能还有写不足之处,有些bug没调出来(如:对在线人数的控制),希望大佬赐教. 那么话不多说,放码过来: 码云:传送门, ...
- linux下C语言多线程编程实例
用一个实例.来学习linux下C语言多线程编程实例. 代码目的:通过创建两个线程来实现对一个数的递加.代码: //包含的头文件 #include <pthread.h> #include ...
- Linux下c开发 之 线程通信(转)
Linux下c开发 之 线程通信(转) 1.Linux“线程” 进程与线程之间是有区别的,不过Linux内核只提供了轻量进程的支持,未实现线程模型.Linux是一种“多进程单线程”的操作系统.Linu ...
- Linux下c开发 之 线程通信
Linux下c开发 之 线程通信 1.Linux“线程” 进程与线程之间是有区别的,不过Linux内核只提供了轻量进程的支持,未实现线程模型.Linux是一种“多进程单线程”的操作系统.Linux本身 ...
- linux 下C语言学习路线
UNIX/Linux下C语言的学习路线.一.工具篇“公欲善其事,必先利其器”.编程是一门实践性很强的工作,在你以后的学习或工作中,你将常常会与以下工具打交道, 下面列出学习C语言编程常常用到的软件和工 ...
- Linux下C语言编程实现spwd函数
Linux下C语言编程实现spwd函数 介绍 spwd函数 功能:显示当前目录路径 实现:通过编译执行该代码,可在终端中输出当前路径 代码实现 代码链接 代码托管链接:spwd.c 所需结构体.函数. ...
- Linux基础与Linux下C语言编程基础
Linux基础 1 Linux命令 如果使用GUI,Linux和Windows没有什么区别.Linux学习应用的一个特点是通过命令行进行使用. 登录Linux后,我们就可以在#或$符后面去输入命令,有 ...
随机推荐
- luogu 1967 货车运输(最大生成树+LCA)
题意:给出一颗n个点的图,q个询问,每次询问u到v的路径中最小的边最大是多少. 图的最大生成树有一个性质,对于该图的任意两个点,在树中他们之间路径的最小边最大. 由于这个图不一定联通,于是我们对它的联 ...
- 秒杀多线程第八篇 经典线程同步 信号量Semaphore (续)
java semaphore实现: Semaphore当前在多线程环境下被扩放使用,操作系统的信号量是个很重要的概念,在进程控制方面都有应用.Java 并发库 的Semaphore 可以很轻松完成信号 ...
- http2.0可行性研究
一.http2比http1有了更多新特性 1.使用了多路复用的技术,并发量支持比http1大几个数量级: 2.二进制分帧,改善网络延迟情况,提高传输速率: 3.支持header的数据压缩,数据体积变 ...
- 51nod 1277字符串中的最大值(拓展kmp)
题意: 一个字符串的前缀是指包含该字符第一个字母的连续子串,例如:abcd的所有前缀为a, ab, abc, abcd. 给出一个字符串S,求其所有前缀中,字符长度与出现次数的乘积的最大值. 题解 ...
- Day19内容回顾
1,Django请求的生命周期 路由系统-视图函数(获取模板+数据->渲染)->字符串返回给用户 2,路由系统 /index/ 函数或类.as_view() /detail(\d+)/ 函 ...
- hihoCoder #1639 图书馆
题目大意 给定 $n$($1\le n\le 1000$)个正整数 $a_1, a_2, \dots, a_n$($a_i \le 10^{12}$),令 $s$ 为这 $n$ 个数之和.求 $$ \ ...
- 【BZOJ5319】军训列队(主席树)
[BZOJ5319]军训列队(主席树) 题面 BZOJ 洛谷 题解 一眼题既视感... 首先很明显,每次询问的结果显然是做一次离散. 然后直接上主席树就好了... 查询答案的方式也很简单 考虑一下那个 ...
- 洛谷 P2233 [HNOI2002]公交车路线 解题报告
P2233 [HNOI2002]公交车路线 题目背景 在长沙城新建的环城公路上一共有8个公交站,分别为A.B.C.D.E.F.G.H.公共汽车只能够在相邻的两个公交站之间运行,因此你从某一个公交站到另 ...
- POJ.3279 Fliptile (搜索+二进制枚举+开关问题)
POJ.3279 Fliptile (搜索+二进制枚举+开关问题) 题意分析 题意大概就是给出一个map,由01组成,每次可以选取按其中某一个位置,按此位置之后,此位置及其直接相连(上下左右)的位置( ...
- 代码收藏系列--javascript--日期函数
/** * 获取当前时间的简短函数 * @returns {String} * @@example getTimeStamp() 结果是:2017-07-12 09:21:30 */ function ...