三 Linux--多线程( 三 )

注意:

  • 生产者之间需要一个互斥量,消费者之间也需要一个互斥量
  • 生产者和消费者的个数可以自己调整宏变量
运行结果如下:
三 Linux--多线程

文章插图
POSIX信号量介绍POSIX信号量: 该信号量允许进程和线程同步对共享资源的访问 。同时也可以用于实现线程间同步 。
总结几点:
  • 是什么? 信号量本质是一个计数器,描述临界资源的有效个数 。申请一个资源就对信号量减1(P操作) , 释放一个资源就对信号量加1(V操作)
  • 为什么? 临界资源可以看成很多份,互相不冲突且高效
  • 怎么用? 可以使用信号量的相关接口,来申请信号量和释放信号量(下面详细介绍)
相关接口的介绍下面要介绍的POSIX信号量相关接口都是在semaphore.h的头文件中 。信号量是一个类型为sem_t的变量
  • 初始化信号量
int sem_init(sem_t *sem, int pshared, unsigned int value);功能: 创建一个信号量并初始化它的值 。一个无名信号量在被使用前必须先初始化参数: sem:信号量的地址 pshared:等于0,信号量在线程间共享(常用) 。不等于0 , 信号量在进程间共享 value:信号量的初始值返回值: 成功:0 失败:-1信号量的初始值就是可用资源的个数
  • 销毁信号量
int sem_destroy(sem_t *sem);功能: 删除sem标识的信号量参数: sem:信量地址返回值: 成功:0 失败:-1
  • 信号量P操作(减一)
int sem_wait(sem_t *sem);功能: 将信号量的值减1 。操作前 , 先检查信号量(sem)的值是否为0,若信号量为0,此函数会阻塞,直到信号量大于0时才进行减一操作参数: sem:信号量的地址返回值: 成功:0 失败:-1int sem_trywait(sem_t *sem); 以非阻塞的方式来对信号量进行减1操作 若操作前,信号量的值等于0,则对信号量的操作失败,函数立即返回int sem_timedwait(sem_t* sem,const struct timespec *abs_timeout); 限时尝试将信号量的值减1 abs_timeout:绝对时间
  • 信号量V操作(加一)
int sem_post(sem_t *sem);功能: 将信号量的值加1并发出信号唤醒等待线程(sem_wait())参数: sem:信号量的地址 。返回值:成功:0
  • 获取信号量的值
int sem_getvalue(sem_t *sem,int *Sval);功能: 获取sem标识的信号量的值,保存在sval中参数: sem:信号量地址 sval:保存信号值的地址返回值: 成功:0 失败:-1举个简单的例子:
三 Linux--多线程

文章插图
初始化信号量的资源数是1,意思就是系统中只有一份资源,线程1如果要申请这份资源,首先要进行p操作 , sem_wait()函数,那么资源数-1,此时资源数是0,说明系统中没有可用的资源 , 其他线程在进行p操作的时候就会阻塞,线程1执行完毕,执行v操作,资源数+1,系统中的资源被释放出来,线程2此时解除阻塞状态,步骤和线程1一样 。
代码示例:
#include <iostream>#include <unistd.h>#include <pthread.h>#include <semaphore.h>using namespace std;sem_t sem;void* run1(void* arg){while (1){sem_wait(&sem);cout << "run1 is running..." << endl;sem_post(&sem);sleep(1);}}void* run2(void* arg){while (1){sem_wait(&sem);cout << "run2 is running..." << endl;sem_post(&sem);sleep(1);}}int main(){sem_init(&sem, 0, 1);pthread_t t1, t2;pthread_create(&t1, nullptr, run1, nullptr);pthread_create(&t2, nullptr, run2, nullptr);sem_destroy(&sem);pthread_join(t1, nullptr);pthread_join(t2, nullptr);return 0;}运行结果如下:
三 Linux--多线程

文章插图
注意:当信号量的初始值为1的时候,就相当于一把互斥锁
基于环形队列的生产消费模型环形队列介绍环形队列: 环形队列和普通队列的区别就是,这种队列是一种环形的结构 , 有一个头指针和一个尾指针维护环中一小段队列 。
三 Linux--多线程

文章插图
环形结构起始状态和结束状态都是一样的,不好判断为空或者为满,所以可以通过加计数器或者标记位来判断满或者空 。另外也可以预留一个空的位置,作为满的状态 。
这就类似于数据结构中学的循环队列类似 。
三 Linux--多线程

文章插图
因为信号量就是一个计数器,所以我们可以通过信号量来实现多线程间的同步过程 。

推荐阅读