当前位置: 首页 > news >正文

台州网站建设公司哪个好在别人网站挂黑链

台州网站建设公司哪个好,在别人网站挂黑链,网页制作包括哪些内容,windows软件开发工具一. 信号量概述 1.1 信号量的概念 在多线程场景下#xff0c;我们经常会提到临界区和临界资源的概念#xff0c;如果临界区资源同时有多个执行流进入#xff0c;那么在多线程下就容易引发线程安全问题。 为了保证线程安全#xff0c;互斥被引入#xff0c;互斥可以保证…一. 信号量概述 1.1 信号量的概念 在多线程场景下我们经常会提到临界区和临界资源的概念如果临界区资源同时有多个执行流进入那么在多线程下就容易引发线程安全问题。 为了保证线程安全互斥被引入互斥可以保证在同一时刻只有一个执行流进入临界区访问临界资源由于整个临界区都只允许一个执行流进入我们可以认为互斥是将临界区当做一个整体来使用的。 但是如图1.1假设下面这种场景一个临界区资源被分为N个小区域每个小区域都有特定的数据如果多个执行流同时访问同一个小区域那么线程之间就会相互干扰存在线程不安全问题但如果多个执行流在某一时刻访问不同的小区域保证每个小区域在同一时刻不会有多个执行流访问那么即使有多个执行流进入临界区也不存在线程安全问题。 结论多个同时进入临界区的执行流如果不访问同一块资源就不会有线程不安全问题。 图1.1 多线程访问临界资源线程安全和不安全的场景 为了让多跟线程能同时访问临界资源并且保证线程安全信号量的概念被引入以保证进入临界区的线程不访问同一块临界资源以此来提高多线程的效率。 信号量的本质为计数器count用于表示临界区还有多少资源。 当某个执行流要访问临界区资源前要先申请信号量计数器count--申请信号量的操作被称为P操作如果临界区内还有资源那么申请信号量就会成功计数器count--拿到信号量之后该线程执行流就拥有了进入临界区的权利。 申请到了信号量本质是一种资源预定机制并不是说申请到了信号量已经在访问临界资源了但申请到了信号量的执行流具有访问临界资源的权利可以在适当的时候访问临界资源。 当执行流访问完临界资源后要释放信号量计数器count释放信号量的操作被称为V操作这样之前等待信号量的资源就可以拿到信号量以进入临界区访问临界资源。 至于申请到了信号量后访问的是那一块临界资源信号量本身并无法指定需要程序员编程决定。 结论(1). 信号量本质为计数器用于表示还剩多少临界资源  (2). 访问临界资源前要通过申请信号量来预定临界资源信号量计数器--称为P操作  (3). 离开临界区要释放信号量信号量计数器被称为V操作  (4). 如果临界区内没有剩余资源此时信号量为0线程申请不到信号量就会被阻塞。  这里借助生活中的场景来辅助理解信号量。假设某明星演唱会现场观看的座位数为200这200个现场座位为共享资源每个座位就是临界区内的一小块资源。当现场观看的票还没有卖出时剩余资源数为200初始信号量为200。 如果此时有人买走了一张票那么他就预定了一个现场座位即预定一份共享资源即使他不去现场观看那么这个座位也属于他其他人不能占用预定一张票就是申请一个信号量计数器count--由200变为199。 如果某时200个座位都被预定了剩余资源就变为0类似于信号量为0此时再有人想预定现场座位就无法预定成功这与线程在信号量为0的时候无法预定临界资源类似。 如果演唱会结束或某人退票那么就释放了一个临界区资源信号量计数器count这时座位就又可以预定了类似于多线程中某一线程执行流离开临界区释放信号量这个信号量就可以被之前因为信号量为0而被阻塞的线程拿到进入临界区访问资源。 1.2 信号量相关函数 信号量的初始化 通过函数sem_init可初始化信号量。初始化信号量的时候就应当指定初始值即有多少临界资源可以被不同执行流访问。 sem_init -- 信号量初始化函数 函数原型sem_init(sem_t *sem, int pshared, unsigned int value); 头文件#include semaphore.h 函数参数 sem -- 被初始化的信号量的地址pshared -- 0表示同一进程下的线程间共享1表示进程间共享value -- 信号量的初始值 返回值成功返回0失败返回-1并设置错误码。 信号量等待 通过sem_wait函数可以让线程等待信号量。如果当前信号量不为0线程申请等待到了信号量那么这个线程就预定了一份临界资源信号量计数器--。如果当前信号量为0即没有剩余的临界资源了线程就需要等待一份临界资源被释放才能申请到信号量。申请信号量调用sem_wait的操作被称为P操作。 sem_wait函数 -- 申请等待信号量 函数原型int sem_wait(sem_t *sem) 头文件#includesemaphore.h 函数参数sem -- 被等待的信号的地址 返回值成功返回0失败返回-1并设置错误码。 信号量释放 通过sem_post函数可以实现释放信号量资源。如果某一线程申请到了信号量并访问了临界资源访问临界资源完成后要释放信号量让其他正在等待信号量的线程可以拿到信号量并访问临界资源。释放信号量信号量计数器这样的操作被称为V操作。 sem_post函数 -- 释放信号量 函数原型int sem_post(sem_t *sem) 头文件#include semaphore.h 函数参数sem -- 被等待的信号的地址。 返回值函数执行成功返回0失败返-1并设置错误码 二. 通过环形队列实现生产与消费者模型 2.1 环形结构解析 图2.1为环形队列的逻辑结构和物理结构图在其底层实现代码中依旧是采用线性数组来实现的只不过我们通过特定的计算机代码来使其行为与首尾相连的环形结构一致。 图2.1 环形队列的物理结构和逻辑结构 假设环形队列能够容纳N个元素那么我们在拿到下标为index的位置时如要找到其后面第k个元素的位置计算方法为(index k) % N。 有两种方法可以判断环形队列是空还是满 用计数器来辅助如果计数器count 0环形队列就是空如果等同于环形队列的最大容量N即count N就是满。间隔空位相比于环形队列的最大容量多开辟一个数据空间采用两个指针first和last记录首个元素位置和末尾元素后面的位置如果last  fisrt那么环形队列为空如果(last 1) % N first 成立那么环形队列为满图2.2为这种方法的。 图2.2 环形队列满和空的情况 2.2 生产消费者模型与环形队列的联系 如果采用阻塞队列的方式来实现生产与消费者模型由于C STL中提供的queue不向用户暴露底层实现并且将阻塞队列视为一个整体来进行数据的写入和读取造成了某一时刻只允许一个生产者线程或一个消费者线程访问临界资源阻塞队列为了保证线程安全生产者写数据和消费者读数据不能够同时进行。 如图2.3所示假设我们希望向p_step所指向的位置写数据从c_step所指向的位置读数据由于p_step和c_step所指向的是环形队列的不同位置此时生产者和消费者线程如果并发执行不会出现线程不安全问题因为这两个执行流访问的是临界资源的不同区域。 但是如果p_step和c_step指向环形队列的同一位置此时生产者线程和消费者线程并发执行则会访问临界资源的相同区域引发线程不安全问题。 允许一定条件下的生产者线程和消费者线程并发执行可以显著降低等待时间提高程序整体的运行效率。 图2.3 生产与消费者线程可以并发执行和不能并发执行的场景 3.3 基于环形队列的生产与消费者模型实现代码 在程序中可以采用信号量的方式来决定是否让生产者线程或消费者线程阻塞等待我们假设环形队列的最大容量为N那么就定义两个信号量 _sem_space空间信号量表示是否还有剩余空间初值设为N。_sem_data数据信号量表示是否还有可读数据资源初值设为0。 当生产者要向环形队列中写数据时要先申请空间信号量如果申请空间信号量成功说明环形队列中有剩余空间才能向环形队列中写数据当访问完临界资源后要释放数据信号量唤醒因阻塞队列中没有数据而等待数据信号量的消费者线程。 当消费者从环形队列中读取数据时要先申请数据信号量如果申请成功说明环形队列中有可读数据这时消费者线程才能够读取环形队列中的数据当访问完临界资源后要释放空间信号量唤醒因环形队列没有空间而阻塞等待空间信号量的生产者线程。 虽然信号量也是临界资源但是对信号量的/--操作是原子的所以不会存在线程不安全问题。 代码3.1头文件Sem.hpp -- 封装信号量 #pragma once #include iostream #include semaphore.h// 封装用于操作信号量的类 class Sem { public:// 构造函数实现初始化信号量Sem(int pshared, int value){sem_init(_sem, pshared, value);}// 析构函数销毁信号量~Sem(){sem_destroy(_sem);}// 等待信号量 -- p操作void p(){sem_wait(_sem);}// 释放信号量 -- v操作void v(){sem_post(_sem);}private:sem_t _sem; // 信号量 }; 代码3.2头文件RingQueue.hpp -- 实现阻塞队列 #pragma once#include iostream #include vector #include pthread.h #include Sem.hppint g_DFL_CAPACITY 5; // 信号量默认初值templateclass T class RingQueue { public:// 构造函数RingQueue(int capacity g_DFL_CAPACITY): _ring_queue(capacity, T()), _capacity(capacity), _p_step(0), _c_step(0), _sem_data(0), _sem_space(capacity){ // 初始化生产者线程和消费者线程互斥锁pthread_mutex_init(_c_mtx, nullptr);pthread_mutex_init(_p_mtx, nullptr);}// 析构函数~RingQueue(){// 销毁生产者线程和消费者线程互斥锁pthread_mutex_destroy(_c_mtx);pthread_mutex_destroy(_p_mtx);}// 生产者写数据函数void push(const T val){// 1. 申请空间信号量 -- p操作_sem_space.p();// 2. 加锁 - 写数据 - 解锁pthread_mutex_lock(_p_mtx); // 加锁_ring_queue[_p_step] val; // 写数据_p_step % _capacity; // 更新下标pthread_mutex_unlock(_p_mtx); // 解锁// 3. 释放数据信号量_sem_data.v();}// 消费者读数据函数data为输出型参数void pop(T* data){// 1. 申请数据信号量_sem_data.p();// 2. 加锁 - 读数据 - 解锁pthread_mutex_lock(_c_mtx); // 加锁*data _ring_queue[_c_step]; // 读数据_c_step % _capacity; // 更新下标pthread_mutex_unlock(_c_mtx); // 解锁// 3. 释放空间信号量_sem_space.v();}private:std::vectorT _ring_queue; // 用线性表模拟实现的环形队列int _capacity; // 环形队列容量int _p_step; // 生产者向环形队列写数据的下标位置int _c_step; // 消费者从环形队列中读取数据的下标pthread_mutex_t _c_mtx; // 用于控制消费者线程的互斥锁pthread_mutex_t _p_mtx; // 用于控制生产者线程的互斥锁Sem _sem_data; // 用于表示环形队列中现有数据的信号量Sem _sem_space; // 用于表示环形队列中剩余空间的信号量 }; 代码3.3ConProd.cc文件 -- 生产消费者模型main函数所在源文件 #include iostream #include pthread.h #include unistd.h #include RingQueue.hpp// 消费者线程入口函数 void* consume(void* args) {RingQueueint *prq (RingQueueint*)args;// 间隔1s从环形队列中读数据int data;while(true){prq-pop(data);std::cout 消费数据 data std::endl;sleep(1);}return nullptr; }void* product(void* args) {RingQueueint *prq (RingQueueint*)args;// 死循环向环形队列中写数据int a 0;while(true){std::cout 生产数据 a std::endl;prq-push(a);a;}return nullptr; }int main() {RingQueueint *prq new RingQueueint();// 闯将两个生产者线程三个消费者线程pthread_t p[2], c[3];pthread_create(p, nullptr, product, (void*)prq);pthread_create(p 1, nullptr, product, (void*)prq);pthread_create(c, nullptr, consume, (void*)prq);pthread_create(c 1, nullptr, consume, (void*)prq);pthread_create(c 2, nullptr, consume, (void*)prq);// 阻塞等待生产者消费者线程退出pthread_join(p[0], nullptr);pthread_join(p[1], nullptr);pthread_join(c[0], nullptr);pthread_join(c[1], nullptr);pthread_join(c[2], nullptr);return 0; } 三. 总结 信号量的本质为一计数器用于表示临界区内还剩多少资源。通过使用信号量可让多个线程执行流去访问临界资源的不同区域达到某时刻多个执行流进入临界区但不会造成线程不安全的目的。线程进入临界区前要先申请信号量在离开临界区后要释放信号量。
http://www.tj-hxxt.cn/news/224466.html

相关文章:

  • 网站建设厘金手指排名十九国外做免费网站的
  • 在线修图网站玖玖建筑网
  • 郑州网站建设维护公司建设网站是公司资产
  • 怎样创建网站以及建站流程是什么wordpress首页标题修改
  • 网络推广建议网络优化的内容包括哪些方面
  • 全网推广公司成都百度网站排名优化
  • 营销网站建设哪家好网站制作小常识
  • 网站建设策划书是有谁编写的wordpress分站点
  • 邯郸网站设计怎么用商标网官方查询官网
  • 站群管理系统wordpress中文标签云
  • 做logo好的网站小榄网站建设
  • 柳城网站开发企业网站功能模块
  • 温州微网站制作多少钱做网站的一些好处
  • 宝塔网站做301重定向自学考试
  • 买了一个域名如何做网站wordpress 更改数据库密码
  • 用织梦做的网站下载地址wordpress 身份认证
  • 英语培训学校网站建设多少钱wordpress 邮件写文章
  • 做视频网站赚钱嘛南京整站优化
  • 廊坊网站制作策划网站嵌入百度地图
  • 浑南区建设局网站win2012 网站建设
  • 额尔古纳网站建设手机上怎么做网站创业
  • 招聘网站内容建设加强网络舆情监测
  • 做海报的网站类似于创客贴网站怎么做下载网页代码吗
  • 权威数据统计网站餐饮培训
  • 深圳手机网站开发wordpress安装使用教程
  • 一个网站费用wordpress炫酷网页
  • 网站建设销售信广告设计是做什么
  • 开源网站系统安全性哪个网站做设计可以挣钱
  • 课程培训网站模板下载百度网页版主页链接
  • 长沙模板建站欢迎咨询广州佛山app网站商城制作