• LINUX系统编程:基于环形队列和信号量的生产者消费者模型


    目录

    1.环形队列

    2.加上信号量的理解

    3.代码


    1.环形队列

    环形队列使用vector封装出来的。

    环形队列可以实现并发生产和消费,就是在消费的同时也可以生产。

    这个是建立在生产者消费者位置不重合的情况下。

    因为位置重合之后,环形队列为空或者满,

    为空的时,只能让生产者先生产,消费者后消费,

    为满时,消费者先消费,生产者后生产。

    如何实现环形的效果

    当下标遍历到vector末尾的时候, 下标 %=判断环形队列为空还是为满 vector容量,下标就回到数组的开始。

    当生产者消费者重合时

    1.队列为空(访问环形队列,让生产者先生产)

    2.队列为满(访问环形队列,让消费者先消费)

    当生产者与消费者不重合时

    队列一定不为空&&不为满,这个时候生产者可以生产,消费者可以消费。

    2.加上信号量的理解

    生产者只关心环形队列有没有空间让他生产

    消费者只关心环形队列有没有数据让他消费

    信号量是一种资源预定机制,预定成功之后肯定会有空间和数据,给消费者和生产者

    所以生产者在生产之前要对空间的信号量进行p操作,生产完成之后要对数据的信号量进行v操作

    所以消费者在生产之前要对数据的信号量进行p操作,消费完成之后要对空间的信号量进行v操作

    3.代码

    ringqueue.hpp

    1. #ifndef __RINGQUEUEHPP__
    2. #define __RINGQUEUEHPP__
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include"Task.hpp"
    8. #include
    9. #include
    10. template<class T>
    11. class ringqueue
    12. {
    13. private:
    14. void p(sem_t &sem)
    15. {
    16. int ret = sem_wait(&sem);
    17. if(ret == -1)
    18. {
    19. std::cout<< strerror(errno) <
    20. }
    21. }
    22. void v(sem_t &sem)
    23. {
    24. int ret = sem_post(&sem);
    25. if(ret == -1)
    26. {
    27. std::cout<< strerror(errno) <
    28. }
    29. }
    30. public:
    31. ringqueue(int cap = 8)
    32. :_ringqueue(cap)
    33. ,_cap(cap)
    34. ,p_step(0)
    35. ,c_step(0)
    36. {
    37. sem_init(&_room,0,cap);
    38. sem_init(&_data,0,0);
    39. pthread_mutex_init(&c_mutex,nullptr);
    40. pthread_mutex_init(&p_mutex,nullptr);
    41. }
    42. //生产者向队列里生产
    43. void enqueue(T in)
    44. {
    45. p(_room); // 申请空间
    46. pthread_mutex_lock(&p_mutex);
    47. _ringqueue[p_step++] = in;
    48. p_step %= _cap;
    49. pthread_mutex_unlock(&p_mutex);
    50. v(_data); // 生产之后资源++
    51. }
    52. void pop(T &out)
    53. {
    54. //int roomnum = 0;
    55. //int datanum = 0;
    56. //sem_getvalue(&_room,&roomnum);
    57. //sem_getvalue(&_data,&datanum);
    58. //std::cout<< roomnum <<" " <
    59. p(_data); //申请资源
    60. pthread_mutex_lock(&c_mutex);
    61. out = _ringqueue[c_step++];
    62. c_step %= _cap;
    63. pthread_mutex_unlock(&c_mutex);
    64. v(_room);
    65. }
    66. ~ringqueue()
    67. {
    68. sem_destroy(&_room);
    69. sem_destroy(&_data);
    70. pthread_mutex_destroy(&p_mutex);
    71. pthread_mutex_destroy(&c_mutex);
    72. }
    73. private:
    74. std::vector _ringqueue;
    75. int _cap;//容量
    76. int p_step ;//生产者下次生产的位置
    77. int c_step ;//消费者下次消费的位置
    78. sem_t _room; //空间
    79. sem_t _data; //资源
    80. pthread_mutex_t p_mutex; //为了多生产之间的互斥关系
    81. pthread_mutex_t c_mutex; //为了多消费之间的互斥关系
    82. };
    83. #endif

    Task.hpp

    1. #ifndef __TASKHPP__
    2. #define __TASKHPP__
    3. #include
    4. #include
    5. class Task
    6. {
    7. public:
    8. Task():taskname("未知任务"){}
    9. Task(std::string name)
    10. :taskname(name)
    11. {}
    12. void excute()
    13. {
    14. std::cout<<"Excute " << taskname <
    15. }
    16. std::string & name()
    17. {
    18. return taskname;
    19. }
    20. private:
    21. std::string taskname;
    22. };
    23. #endif

    Main.cc

    1. #include "Task.hpp"
    2. #include "ringqueue.hpp"
    3. #include
    4. #include
    5. #include
    6. #include
    7. #include
    8. #include
    9. std::vector Taskarr{"Download", "UPLoad", "cacluate"};
    10. void product(void* args)
    11. {
    12. ringqueue* rq = (ringqueue*)args;
    13. srand(time(nullptr));
    14. while (true)
    15. {
    16. sleep(1);
    17. Task task(Taskarr[rand() % 3]);
    18. rq->enqueue(task);
    19. std::cout << "product task "<< task.name() << std::endl;
    20. }
    21. }
    22. //void consum(ringqueue &rq)
    23. //用指針的方式传递参数,把ringqueue的指针传过来,
    24. void consum(void* args)
    25. {
    26. ringqueue* rq = (ringqueue*)args;
    27. sleep(6);
    28. while (true)
    29. {
    30. sleep(1);
    31. Task task;
    32. rq->pop(task);
    33. task.excute();
    34. }
    35. }
    36. //是不是这里的问题 这里传过去的时候发生了拷贝
    37. //是的
    38. void product_start(std::vector &threadss, ringqueue &rq, int num)
    39. {
    40. for (int i = 0; i < num; i++)
    41. {
    42. threadss.emplace_back(product, (void*)&rq);
    43. }
    44. }
    45. void consumer_start(std::vector &threadss, ringqueue &rq, int num)
    46. {
    47. for (int i = 0; i < num; i++)
    48. {
    49. threadss.emplace_back(consum, (void*)&rq);
    50. }
    51. }
    52. void Waitall(std::vector &threadss)
    53. {
    54. for (auto &thread : threadss)
    55. {
    56. thread.join();
    57. }
    58. }
    59. int main()
    60. {
    61. std::vector threadss;
    62. ringqueue rq(5);
    63. product_start(threadss, rq,3);
    64. consumer_start(threadss, rq, 5);
    65. Waitall(threadss);
    66. return 0;
    67. }

  • 相关阅读:
    选择排序超详细讲解C语言
    Android提取视频或音频
    cas244193-52-0|[C8MIm]BF4|1-辛基-3-甲基咪唑四氟硼酸盐离子液体分子式:C12H23BF4N2
    HTTP HTTPS SSL TLS
    WAVE音频格式及及转换代码
    17:00面试,17:09就出来了 ,问的实在是太...
    00Hadoop数据仓库平台
    metaRTC5.0实现webrtc的TURN支持
    APS高级排产在休闲食品行业的应用
    黑马redis学习记录Ⅲ SpringDataRedis客户端
  • 原文地址:https://blog.csdn.net/W2155/article/details/140389324