目录
本质:内核中的一个计数器+等待队列
操作:PV操作
P操作:判断计数器:
大于0,则返回,返回前计数器-1;
小于等于0则阻塞。
V操作:计数器计数+1,唤醒一个阻塞的执行流
作用:实现进程或线程间的同步与互斥
同步实现:计数器对资源进行计数
获取资源前,进行P操作;
产生一个资源,进行V操作;
互斥实现:计数器置1,表示资源只有一个
访问资源前,进行P操作;
访问资源完毕后,进行V操作。
相同点:
信号量与条件变量都可以实现同步
区别:
信号量本身带有计数器,自身提供了资源获取条件判断的功能;
条件变量,条件判断需要用户自己实现。
sem_t;
int sem_init(sem_t *sem, int pshared, int val);
sem:信号量变量;
pshared: 0用于线程间;非0用于进程间;
val:信号量的初始值;
返回值:
成功,返回0;失败,返回-1。
int sem_wait(sem_t *sem);阻塞
int sem_trywait(sem_t *sem);非阻塞
int sem_timedwait(sem_t *sem);有时长限制的阻塞。
int sem_post(sem_t *sem);
int sem_destroy(sem_t *sem);
- template <class T>
- class CircularQueue {
- pricate:
- //实现环形队列
- std::vector
_array; - int _capacity;
- int _front = 0;
- int _rear = 0;
-
- //实现同步
- sem_t _sem_idle;//对队列空闲空间计数
- sem_t _sem_data;//对有效数据节点计数
-
- //实现互斥
- sem_t _sem_lock;//实现互斥锁
- };
- #include
- #include
- #include
- #include
- #include
-
- #define MAX_QUEUE 5
- #define PRODUCER 4
- #define CONSUMER 4
-
- template <class T>
- class CircularQueue {
- private:
- std::vector
_array; - int _front;
- int _rear;
- int _capacity;
-
- sem_t _sem_idle;//对空闲空间计数
- sem_t _sem_data;//对数据空间计数
- sem_t _sem_lock;//实现互斥锁
-
- public:
- CircularQueue(int cap = MAX_QUEUE)
- : _capacity(cap)
- ,_front(0)
- ,_rear(0)
- ,_array(cap)
- {
- sem_init(&_sem_idle, 0, cap);
- sem_init(&_sem_data, 0, 0);
- sem_init(&_sem_lock, 0, 1);
- }
-
- ~CircularQueue() {
- sem_destroy(&_sem_idle);
- sem_destroy(&_sem_data);
- sem_destroy(&_sem_lock);
- }
-
- bool Push(const T data) {
- //1.P操作,对空闲空间计数进行判断
- sem_wait(&_sem_idle);
- //2.获取锁
- sem_wait(&_sem_lock);
- //3.放入数据
- _array[_front] = data;
- _front = (_front + 1) % _capacity;
- //4.解锁
- sem_post(&_sem_lock);
- //5.V操作,对数据空间进行计数+1
- sem_post(&_sem_data);
- }
-
- bool Pop(T *data) {
- //1.P操作,对数据空间计数进行判断
- sem_wait(&_sem_data);
- //2.获取锁
- sem_wait(&_sem_lock);
- //3.获取数据
- *data = _array[_rear];
- _rear = (_rear + 1) % _capacity;
- //4.解锁
- sem_post(&_sem_lock);
- //5.V操作,对空闲空间计数+1
- sem_post(&_sem_idle);
- }
-
- };
-
- void *Consumer(void *arg) {
- CircularQueue<int> *p = (CircularQueue<int>*)arg;
- while (1) {
- int data;
- p -> Pop(&data);
- printf("Consumer get data: %d\n", data);
- }
- }
-
- void *Producer(void *arg) {
- CircularQueue<int> *p = (CircularQueue<int>*)arg;
- int data = 1;
- while (1) {
- p -> Push(data);
- printf("Producer put data: %d\n", data);
- ++data;
- }
- }
-
- void Test() {
- int ret;
- pthread_t con_tid[CONSUMER], pro_tid[PRODUCER];
-
- CircularQueue<int> q;
- //Create consumer threads
- for (int i = 0; i < CONSUMER; ++i) {
- pthread_create(&con_tid[i], NULL, Consumer, (void*)&q);
- if (ret != 0) {
- std::cout<<"Create consumer threads error!"<
- return;
- }
- }
-
- //Create producer threads
- for (int i = 0; i < PRODUCER; ++i) {
- pthread_create(&pro_tid[i], NULL, Producer, (void*)&q);
- if (ret != 0) {
- std::cout<<"Create producer threads error!"<
- return ;
- }
- }
-
- //wait threads
- for (int i = 0; i < CONSUMER; ++i) {
- pthread_join(con_tid[i], NULL);
- }
- for (int i = 0; i < PRODUCER; ++i) {
- pthread_join(pro_tid[i], NULL);
- }
-
- }
-
- int main () {
- Test();
- return 0;
- }
实现效果:

-
相关阅读:
【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