• Linux信号量:POSIX标准接口、实现生产者与消费者模型


    目录

    一、信号量简介

    1.信号量

    2.信号量与条件变量的区别

    二、信号量标准接口POSIX

    1.定义信号量

    2.初始化信号量

    3.P操作

    4.V操作

    5.释放信号量

    三、信号量实现生产者与消费者模型

    1.信号量实现线程安全的环形队列

    2.完整代码


    一、信号量简介

    1.信号量

    本质:内核中的一个计数器+等待队列

    操作:PV操作

            P操作:判断计数器:

                    大于0,则返回,返回前计数器-1;

                    小于等于0则阻塞。

            V操作:计数器计数+1,唤醒一个阻塞的执行流

    作用:实现进程或线程间的同步与互斥

            同步实现:计数器对资源进行计数

                    获取资源前,进行P操作;

                    产生一个资源,进行V操作;

            互斥实现:计数器置1,表示资源只有一个

                    访问资源前,进行P操作;

                    访问资源完毕后,进行V操作。

    2.信号量与条件变量的区别

    相同点:

            信号量与条件变量都可以实现同步

    区别:

            信号量本身带有计数器,自身提供了资源获取条件判断的功能;

            条件变量,条件判断需要用户自己实现。

    二、信号量标准接口POSIX

    1.定义信号量

            sem_t;

    2.初始化信号量

    int sem_init(sem_t *sem, int pshared, int val);

            sem:信号量变量;

            pshared: 0用于线程间;非0用于进程间;

            val:信号量的初始值;

    返回值:

            成功,返回0;失败,返回-1。

    3.P操作

    int sem_wait(sem_t *sem);阻塞

    int sem_trywait(sem_t *sem);非阻塞

    int sem_timedwait(sem_t *sem);有时长限制的阻塞。

    4.V操作

    int sem_post(sem_t *sem);

    5.释放信号量

    int sem_destroy(sem_t *sem);

    三、信号量实现生产者与消费者模型

    1.信号量实现线程安全的环形队列

    1. template <class T>
    2. class CircularQueue {
    3. pricate:
    4. //实现环形队列
    5. std::vector _array;
    6. int _capacity;
    7. int _front = 0;
    8. int _rear = 0;
    9. //实现同步
    10. sem_t _sem_idle;//对队列空闲空间计数
    11. sem_t _sem_data;//对有效数据节点计数
    12. //实现互斥
    13. sem_t _sem_lock;//实现互斥锁
    14. };

    2.完整代码

    1. #include
    2. #include
    3. #include
    4. #include
    5. #include
    6. #define MAX_QUEUE 5
    7. #define PRODUCER 4
    8. #define CONSUMER 4
    9. template <class T>
    10. class CircularQueue {
    11. private:
    12. std::vector _array;
    13. int _front;
    14. int _rear;
    15. int _capacity;
    16. sem_t _sem_idle;//对空闲空间计数
    17. sem_t _sem_data;//对数据空间计数
    18. sem_t _sem_lock;//实现互斥锁
    19. public:
    20. CircularQueue(int cap = MAX_QUEUE)
    21. : _capacity(cap)
    22. ,_front(0)
    23. ,_rear(0)
    24. ,_array(cap)
    25. {
    26. sem_init(&_sem_idle, 0, cap);
    27. sem_init(&_sem_data, 0, 0);
    28. sem_init(&_sem_lock, 0, 1);
    29. }
    30. ~CircularQueue() {
    31. sem_destroy(&_sem_idle);
    32. sem_destroy(&_sem_data);
    33. sem_destroy(&_sem_lock);
    34. }
    35. bool Push(const T data) {
    36. //1.P操作,对空闲空间计数进行判断
    37. sem_wait(&_sem_idle);
    38. //2.获取锁
    39. sem_wait(&_sem_lock);
    40. //3.放入数据
    41. _array[_front] = data;
    42. _front = (_front + 1) % _capacity;
    43. //4.解锁
    44. sem_post(&_sem_lock);
    45. //5.V操作,对数据空间进行计数+1
    46. sem_post(&_sem_data);
    47. }
    48. bool Pop(T *data) {
    49. //1.P操作,对数据空间计数进行判断
    50. sem_wait(&_sem_data);
    51. //2.获取锁
    52. sem_wait(&_sem_lock);
    53. //3.获取数据
    54. *data = _array[_rear];
    55. _rear = (_rear + 1) % _capacity;
    56. //4.解锁
    57. sem_post(&_sem_lock);
    58. //5.V操作,对空闲空间计数+1
    59. sem_post(&_sem_idle);
    60. }
    61. };
    62. void *Consumer(void *arg) {
    63. CircularQueue<int> *p = (CircularQueue<int>*)arg;
    64. while (1) {
    65. int data;
    66. p -> Pop(&data);
    67. printf("Consumer get data: %d\n", data);
    68. }
    69. }
    70. void *Producer(void *arg) {
    71. CircularQueue<int> *p = (CircularQueue<int>*)arg;
    72. int data = 1;
    73. while (1) {
    74. p -> Push(data);
    75. printf("Producer put data: %d\n", data);
    76. ++data;
    77. }
    78. }
    79. void Test() {
    80. int ret;
    81. pthread_t con_tid[CONSUMER], pro_tid[PRODUCER];
    82. CircularQueue<int> q;
    83. //Create consumer threads
    84. for (int i = 0; i < CONSUMER; ++i) {
    85. pthread_create(&con_tid[i], NULL, Consumer, (void*)&q);
    86. if (ret != 0) {
    87. std::cout<<"Create consumer threads error!"<
    88. return;
    89. }
    90. }
    91. //Create producer threads
    92. for (int i = 0; i < PRODUCER; ++i) {
    93. pthread_create(&pro_tid[i], NULL, Producer, (void*)&q);
    94. if (ret != 0) {
    95. std::cout<<"Create producer threads error!"<
    96. return ;
    97. }
    98. }
    99. //wait threads
    100. for (int i = 0; i < CONSUMER; ++i) {
    101. pthread_join(con_tid[i], NULL);
    102. }
    103. for (int i = 0; i < PRODUCER; ++i) {
    104. pthread_join(pro_tid[i], NULL);
    105. }
    106. }
    107. int main () {
    108. Test();
    109. return 0;
    110. }

    实现效果:

     

  • 相关阅读:
    【Java】Spring Cloud OAuth2之密码模式实战
    伯俊ERP和金蝶云星空接口打通对接实战
    修改Ehcache缓存中取到的值,缓存中的值也被修改了
    ros rviz显示orb-slam2保存的轨迹
    剑指offer——JZ27 二叉树的镜像 解题思路与具体代码【C++】
    翻译:REST 和 gRPC 详细比较
    LeetCode每日一题——667. 优美的排列 II
    鸿蒙OS应用开发之显示图片组件6
    java计算机毕业设计美容院业务管理系统源码+系统+mysql数据库+lw文档
    【Android】了解强引用、软引用、弱引用、虚引用
  • 原文地址:https://blog.csdn.net/m0_63020222/article/details/127457333