转自:http://blog.chinaunix.net/uid-28458801-id-4262445.html

操作系统:ubuntu10.04

前言:
    在嵌入式开发中,只要是带操作系统的,在其上开发产品应用,基本都需要用到多线程。
    为了提高效率,尽可能的提高并发率。因此,线程之间的通信就是问题的核心。
    根据当前产品需要,使用 环形缓冲区 解决。

一,环形缓冲区的实现
    1,cbuf.h

点击(此处)折叠或打开

  1. #ifndef __CBUF_H__
  2. #define __CBUF_H__
  3. #ifdef __cplusplus
  4. extern "C" {
  5. #endif
  6. /* Define to prevent recursive inclusion
  7. -------------------------------------*/
  8. #include "types.h"
  9. #include "thread.h"
  10. typedef    struct _cbuf
  11. {
  12. int32_t        size;            /* 当前缓冲区中存放的数据的个数 */
  13. int32_t        next_in;        /* 缓冲区中下一个保存数据的位置 */
  14. int32_t        next_out;        /* 从缓冲区中取出下一个数据的位置 */
  15. int32_t        capacity;        /* 这个缓冲区的可保存的数据的总个数 */
  16. mutex_t        mutex;            /* Lock the structure */
  17. cond_t        not_full;        /* Full -> not full condition */
  18. cond_t        not_empty;        /* Empty -> not empty condition */
  19. void        *data[CBUF_MAX];/* 缓冲区中保存的数据指针 */
  20. }cbuf_t;
  21. /* 初始化环形缓冲区 */
  22. extern    int32_t        cbuf_init(cbuf_t *c);
  23. /* 销毁环形缓冲区 */
  24. extern    void        cbuf_destroy(cbuf_t    *c);
  25. /* 压入数据 */
  26. extern    int32_t        cbuf_enqueue(cbuf_t *c,void *data);
  27. /* 取出数据 */
  28. extern    void*        cbuf_dequeue(cbuf_t *c);
  29. /* 判断缓冲区是否为满 */
  30. extern    bool        cbuf_full(cbuf_t    *c);
  31. /* 判断缓冲区是否为空 */
  32. extern    bool        cbuf_empty(cbuf_t *c);
  33. /* 获取缓冲区可存放的元素的总个数 */
  34. extern    int32_t        cbuf_capacity(cbuf_t *c);
  35. #ifdef __cplusplus
  36. }
  37. #endif
  38. #endif
  39. /* END OF FILE
  40. ---------------------------------------------------------------*/

2,cbuf.c

点击(此处)折叠或打开

  1. #include "cbuf.h"
  2. /* 初始化环形缓冲区 */
  3. int32_t        cbuf_init(cbuf_t *c)
  4. {
  5. int32_t    ret = OPER_OK;
  6. if((ret = mutex_init(&c->mutex)) != OPER_OK)
  7. {
  8. #ifdef DEBUG_CBUF
  9. debug("cbuf init fail ! mutex init fail !\n");
  10. #endif
  11. return ret;
  12. }
  13. if((ret = cond_init(&c->not_full)) != OPER_OK)
  14. {
  15. #ifdef DEBUG_CBUF
  16. debug("cbuf init fail ! cond not full init fail !\n");
  17. #endif
  18. mutex_destroy(&c->mutex);
  19. return ret;
  20. }
  21. if((ret = cond_init(&c->not_empty)) != OPER_OK)
  22. {
  23. #ifdef DEBUG_CBUF
  24. debug("cbuf init fail ! cond not empty init fail !\n");
  25. #endif
  26. cond_destroy(&c->not_full);
  27. mutex_destroy(&c->mutex);
  28. return ret;
  29. }
  30. c->size     = 0;
  31. c->next_in    = 0;
  32. c->next_out = 0;
  33. c->capacity    = CBUF_MAX;
  34. #ifdef DEBUG_CBUF
  35. debug("cbuf init success !\n");
  36. #endif
  37. return ret;
  38. }
  39. /* 销毁环形缓冲区 */
  40. void        cbuf_destroy(cbuf_t    *c)
  41. {
  42. cond_destroy(&c->not_empty);
  43. cond_destroy(&c->not_full);
  44. mutex_destroy(&c->mutex);
  45. #ifdef DEBUG_CBUF
  46. debug("cbuf destroy success \n");
  47. #endif
  48. }
  49. /* 压入数据 */
  50. int32_t        cbuf_enqueue(cbuf_t *c,void *data)
  51. {
  52. int32_t    ret = OPER_OK;
  53. if((ret = mutex_lock(&c->mutex)) != OPER_OK)    return ret;
  54. /*
  55. * Wait while the buffer is full.
  56. */
  57. while(cbuf_full(c))
  58. {
  59. #ifdef DEBUG_CBUF
  60. debug("cbuf is full !!!\n");
  61. #endif
  62. cond_wait(&c->not_full,&c->mutex);
  63. }
  64. c->data[c->next_in++] = data;
  65. c->size++;
  66. c->next_in %= c->capacity;
  67. mutex_unlock(&c->mutex);
  68. /*
  69. * Let a waiting consumer know there is data.
  70. */
  71. cond_signal(&c->not_empty);
  72. #ifdef DEBUG_CBUF
  73. //    debug("cbuf enqueue success ,data : %p\n",data);
  74. debug("enqueue\n");
  75. #endif
  76. return ret;
  77. }
  78. /* 取出数据 */
  79. void*        cbuf_dequeue(cbuf_t *c)
  80. {
  81. void     *data     = NULL;
  82. int32_t    ret     = OPER_OK;
  83. if((ret = mutex_lock(&c->mutex)) != OPER_OK)    return NULL;
  84. /*
  85. * Wait while there is nothing in the buffer
  86. */
  87. while(cbuf_empty(c))
  88. {
  89. #ifdef DEBUG_CBUF
  90. debug("cbuf is empty!!!\n");
  91. #endif
  92. cond_wait(&c->not_empty,&c->mutex);
  93. }
  94. data = c->data[c->next_out++];
  95. c->size--;
  96. c->next_out %= c->capacity;
  97. mutex_unlock(&c->mutex);
  98. /*
  99. * Let a waiting producer know there is room.
  100. * 取出了一个元素,又有空间来保存接下来需要存储的元素
  101. */
  102. cond_signal(&c->not_full);
  103. #ifdef DEBUG_CBUF
  104. //    debug("cbuf dequeue success ,data : %p\n",data);
  105. debug("dequeue\n");
  106. #endif
  107. return data;
  108. }
  109. /* 判断缓冲区是否为满 */
  110. bool        cbuf_full(cbuf_t    *c)
  111. {
  112. return (c->size == c->capacity);
  113. }
  114. /* 判断缓冲区是否为空 */
  115. bool        cbuf_empty(cbuf_t *c)
  116. {
  117. return (c->size == 0);
  118. }
  119. /* 获取缓冲区可存放的元素的总个数 */
  120. int32_t        cbuf_capacity(cbuf_t *c)
  121. {
  122. return c->capacity;
  123. }

二,辅助文件
    为了提高程序的移植性,对线程相关进行封装。
    1,thread.h

点击(此处)折叠或打开

  1. #ifndef __THREAD_H__
  2. #define __THREAD_H__
  3. #ifdef __cplusplus
  4. extern "C" {
  5. #endif
  6. /* Define to prevent recursive inclusion
  7. -------------------------------------*/
  8. #include "types.h"
  9. typedef    struct _mutex
  10. {
  11. pthread_mutex_t        mutex;
  12. }mutex_t;
  13. typedef    struct _cond
  14. {
  15. pthread_cond_t        cond;
  16. }cond_t;
  17. typedef    pthread_t        tid_t;
  18. typedef    pthread_attr_t    attr_t;
  19. typedef    void*    (* thread_fun_t)(void*);
  20. typedef    struct _thread
  21. {
  22. tid_t            tid;
  23. cond_t            *cv;
  24. int32_t            state;
  25. int32_t            stack_size;
  26. attr_t         attr;
  27. thread_fun_t    fun;
  28. }thread_t;
  29. /* mutex */
  30. extern    int32_t        mutex_init(mutex_t    *m);
  31. extern    int32_t        mutex_destroy(mutex_t    *m);
  32. extern    int32_t        mutex_lock(mutex_t    *m);
  33. extern    int32_t        mutex_unlock(mutex_t    *m);
  34. /* cond */
  35. extern    int32_t        cond_init(cond_t    *c);
  36. extern    int32_t        cond_destroy(cond_t    *c);
  37. extern    int32_t        cond_signal(cond_t *c);
  38. extern    int32_t        cond_wait(cond_t    *c,mutex_t *m);
  39. /* thread */
  40. /* 线程的创建,其属性的设置等都封装在里面 */
  41. extern    int32_t        thread_create(thread_t *t);
  42. //extern    int32_t        thread_init(thread_t    *t);
  43. #define    thread_join(t, p)     pthread_join(t, p)
  44. #define    thread_self()        pthread_self()
  45. #define    thread_sigmask        pthread_sigmask
  46. #ifdef __cplusplus
  47. }
  48. #endif
  49. #endif
  50. /* END OF FILE
  51. ---------------------------------------------------------------*/

2,thread.c

点击(此处)折叠或打开

  1. #include "thread.h"
  2. /* mutex */
  3. int32_t        mutex_init(mutex_t    *m)
  4. {
  5. int32_t        ret = OPER_OK;
  6. if((ret = pthread_mutex_init(&m->mutex, NULL)) != 0)
  7. ret = -THREAD_MUTEX_INIT_ERROR;
  8. return ret;
  9. }
  10. int32_t        mutex_destroy(mutex_t    *m)
  11. {
  12. int32_t        ret = OPER_OK;
  13. if((ret = pthread_mutex_destroy(&m->mutex)) != 0)
  14. ret = -MUTEX_DESTROY_ERROR;
  15. return ret;
  16. }
  17. int32_t        mutex_lock(mutex_t    *m)
  18. {
  19. int32_t        ret = OPER_OK;
  20. if((ret = pthread_mutex_lock(&m->mutex)) != 0)
  21. ret = -THREAD_MUTEX_LOCK_ERROR;
  22. return ret;
  23. }
  24. int32_t        mutex_unlock(mutex_t    *m)
  25. {
  26. int32_t        ret = OPER_OK;
  27. if((ret = pthread_mutex_unlock(&m->mutex)) != 0)
  28. ret = -THREAD_MUTEX_UNLOCK_ERROR;
  29. return ret;
  30. }
  31. /* cond */
  32. int32_t        cond_init(cond_t    *c)
  33. {
  34. int32_t        ret = OPER_OK;
  35. if((ret = pthread_cond_init(&c->cond, NULL)) != 0)
  36. ret = -THREAD_COND_INIT_ERROR;
  37. return ret;
  38. }
  39. int32_t        cond_destroy(cond_t    *c)
  40. {
  41. int32_t        ret = OPER_OK;
  42. if((ret = pthread_cond_destroy(&c->cond)) != 0)
  43. ret = -COND_DESTROY_ERROR;
  44. return ret;
  45. }
  46. int32_t        cond_signal(cond_t *c)
  47. {
  48. int32_t        ret = OPER_OK;
  49. if((ret = pthread_cond_signal(&c->cond)) != 0)
  50. ret = -COND_SIGNAL_ERROR;
  51. return ret;
  52. }
  53. int32_t        cond_wait(cond_t    *c,mutex_t *m)
  54. {
  55. int32_t        ret = OPER_OK;
  56. if((ret = pthread_cond_wait(&c->cond, &m->mutex)) != 0)
  57. ret = -COND_WAIT_ERROR;
  58. return ret;
  59. }

三,测试
    1,测试代码

点击(此处)折叠或打开

  1. /*
  2. * cbuf begin
  3. */
  4. #define        OVER    (-1)
  5. static        cbuf_t    cmd;
  6. static        int        line_1[200];
  7. static        int        line_2[200];
  8. //static        int        temp = 0;
  9. static        bool    line1_finish = false;
  10. static        bool    line2_finish = false;
  11. void*    producer_1(void *data)
  12. {
  13. int32_t    i = 0;
  14. for(i = 0; i < 200; i++)
  15. {
  16. line_1[i] = i+1000;
  17. cbuf_enqueue(&cmd, &line_1[i]);
  18. if(0 == (i % 9)) sleep(1);
  19. }
  20. line1_finish = true;
  21. return NULL;
  22. }
  23. void*    producer_2(void *data)
  24. {
  25. int32_t    i = 0;
  26. for(i = 0; i < 200; i++)
  27. {
  28. line_2[i] = i+20000;
  29. cbuf_enqueue(&cmd, &line_2[i]);
  30. if(0 == (i % 9)) sleep(1);
  31. }
  32. line2_finish = true;
  33. return NULL;
  34. }
  35. void*    consumer(void *data)
  36. {
  37. int32_t        *ptr = NULL;
  38. while(1)
  39. {
  40. ptr = cbuf_dequeue(&cmd);
  41. printf("%d\n",*ptr);
  42. if(cbuf_empty(&cmd) && line2_finish && line1_finish)
  43. {
  44. printf("quit\n");
  45. break;
  46. }
  47. }
  48. return NULL;
  49. }
  50. void    test_cbuf_oper(void)
  51. {
  52. pthread_t    l_1;
  53. pthread_t    l_2;
  54. pthread_t    c;
  55. cbuf_init(&cmd);
  56. pthread_create(&l_1,NULL,producer_1,0);
  57. pthread_create(&l_2,NULL,producer_2,0);
  58. pthread_create(&c,NULL,consumer,0);
  59. pthread_join(l_1,NULL);
  60. pthread_join(l_2,NULL);
  61. pthread_join(c,NULL);
  62. cbuf_destroy(&cmd);
  63. }
  64. void    test_cbuf(void)
  65. {
  66. test_cbuf_oper();
  67. }
  68. /*
  69. * cbuf end
  70. */

2,测试结果

四,参考文件
1,《bareos-master》源码
2,《nginx》源码

linux下C语言实现多线程通信—环形缓冲区,可用于生产者(producer)/消费者(consumer)【转】的更多相关文章

  1. linux下c语言的多线程编程

    我们在写linux的服务的时候,经常会用到linux的多线程技术以提高程序性能 多线程的一些小知识: 一个应用程序可以启动若干个线程. 线程(Lightweight Process,LWP),是程序执 ...

  2. linux下c语言实现多线程文件复制【转】

    转自:https://www.cnblogs.com/zxl0715/articles/5365989.html .具体思路 把一个文件分成N份,分别用N个线程copy, 每个线程只读取指定长度字节大 ...

  3. Linux下c语言TCP多线程聊天室

    开发环境:Linux,GCC 相关知识:TCP(博客:传送门),线程 附加:项目可能还有写不足之处,有些bug没调出来(如:对在线人数的控制),希望大佬赐教. 那么话不多说,放码过来: 码云:传送门, ...

  4. linux下C语言多线程编程实例

    用一个实例.来学习linux下C语言多线程编程实例. 代码目的:通过创建两个线程来实现对一个数的递加.代码: //包含的头文件 #include <pthread.h> #include ...

  5. Linux下c开发 之 线程通信(转)

    Linux下c开发 之 线程通信(转) 1.Linux“线程” 进程与线程之间是有区别的,不过Linux内核只提供了轻量进程的支持,未实现线程模型.Linux是一种“多进程单线程”的操作系统.Linu ...

  6. Linux下c开发 之 线程通信

    Linux下c开发 之 线程通信 1.Linux“线程” 进程与线程之间是有区别的,不过Linux内核只提供了轻量进程的支持,未实现线程模型.Linux是一种“多进程单线程”的操作系统.Linux本身 ...

  7. linux 下C语言学习路线

    UNIX/Linux下C语言的学习路线.一.工具篇“公欲善其事,必先利其器”.编程是一门实践性很强的工作,在你以后的学习或工作中,你将常常会与以下工具打交道, 下面列出学习C语言编程常常用到的软件和工 ...

  8. Linux下C语言编程实现spwd函数

    Linux下C语言编程实现spwd函数 介绍 spwd函数 功能:显示当前目录路径 实现:通过编译执行该代码,可在终端中输出当前路径 代码实现 代码链接 代码托管链接:spwd.c 所需结构体.函数. ...

  9. Linux基础与Linux下C语言编程基础

    Linux基础 1 Linux命令 如果使用GUI,Linux和Windows没有什么区别.Linux学习应用的一个特点是通过命令行进行使用. 登录Linux后,我们就可以在#或$符后面去输入命令,有 ...

随机推荐

  1. luogu 1967 货车运输(最大生成树+LCA)

    题意:给出一颗n个点的图,q个询问,每次询问u到v的路径中最小的边最大是多少. 图的最大生成树有一个性质,对于该图的任意两个点,在树中他们之间路径的最小边最大. 由于这个图不一定联通,于是我们对它的联 ...

  2. 秒杀多线程第八篇 经典线程同步 信号量Semaphore (续)

    java semaphore实现: Semaphore当前在多线程环境下被扩放使用,操作系统的信号量是个很重要的概念,在进程控制方面都有应用.Java 并发库 的Semaphore 可以很轻松完成信号 ...

  3. http2.0可行性研究

     一.http2比http1有了更多新特性 1.使用了多路复用的技术,并发量支持比http1大几个数量级: 2.二进制分帧,改善网络延迟情况,提高传输速率: 3.支持header的数据压缩,数据体积变 ...

  4. 51nod 1277字符串中的最大值(拓展kmp)

    题意: 一个字符串的前缀是指包含该字符第一个字母的连续子串,例如:abcd的所有前缀为a, ab, abc, abcd. 给出一个字符串S,求其所有前缀中,字符长度与出现次数的乘积的最大值.   题解 ...

  5. Day19内容回顾

    1,Django请求的生命周期 路由系统-视图函数(获取模板+数据->渲染)->字符串返回给用户 2,路由系统 /index/ 函数或类.as_view() /detail(\d+)/ 函 ...

  6. hihoCoder #1639 图书馆

    题目大意 给定 $n$($1\le n\le 1000$)个正整数 $a_1, a_2, \dots, a_n$($a_i \le 10^{12}$),令 $s$ 为这 $n$ 个数之和.求 $$ \ ...

  7. 【BZOJ5319】军训列队(主席树)

    [BZOJ5319]军训列队(主席树) 题面 BZOJ 洛谷 题解 一眼题既视感... 首先很明显,每次询问的结果显然是做一次离散. 然后直接上主席树就好了... 查询答案的方式也很简单 考虑一下那个 ...

  8. 洛谷 P2233 [HNOI2002]公交车路线 解题报告

    P2233 [HNOI2002]公交车路线 题目背景 在长沙城新建的环城公路上一共有8个公交站,分别为A.B.C.D.E.F.G.H.公共汽车只能够在相邻的两个公交站之间运行,因此你从某一个公交站到另 ...

  9. POJ.3279 Fliptile (搜索+二进制枚举+开关问题)

    POJ.3279 Fliptile (搜索+二进制枚举+开关问题) 题意分析 题意大概就是给出一个map,由01组成,每次可以选取按其中某一个位置,按此位置之后,此位置及其直接相连(上下左右)的位置( ...

  10. 代码收藏系列--javascript--日期函数

    /** * 获取当前时间的简短函数 * @returns {String} * @@example getTimeStamp() 结果是:2017-07-12 09:21:30 */ function ...