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

网站建设电话销售开场白什么主题的网站容易做

网站建设电话销售开场白,什么主题的网站容易做,管理咨询公司收费标准,泰安搜索引擎优化招聘#x1f387;Linux#xff1a; 博客主页#xff1a;一起去看日落吗分享博主的在Linux中学习到的知识和遇到的问题博主的能力有限#xff0c;出现错误希望大家不吝赐教分享给大家一句我很喜欢的话#xff1a; 看似不起波澜的日复一日#xff0c;一定会在某一天让你看见坚持… Linux 博客主页一起去看日落吗分享博主的在Linux中学习到的知识和遇到的问题博主的能力有限出现错误希望大家不吝赐教分享给大家一句我很喜欢的话 看似不起波澜的日复一日一定会在某一天让你看见坚持的意义祝我们都能在鸡零狗碎里找到闪闪的快乐。 目录 1. POSIX信号量1.1 信号量的原理1.2 信号量的概念1.3 信号量函数 2. 二元信号量模拟实现互斥功能 3. 基于环形队列的生产消费模型3.1 空间资源和数据资源3.2 生产者和消费者申请和释放资源3.3 必须遵守的两个规则3.4 代码实现3.5 信号量保护环形队列的原理1. POSIX信号量 1.1 信号量的原理 我们将可能会被多个执行流同时访问的资源叫做临界资源临界资源需要进行保护否则会出现数据不一致等问题。当我们仅用一个互斥锁对临界资源进行保护时相当于我们将这块临界资源看作一个整体同一时刻只允许一个执行流对这块临界资源进行访问。但实际我们可以将这块临界资源再分割为多个区域当多个执行流需要访问临界资源时如果这些执行流访问的是临界资源的不同区域那么我们可以让这些执行流同时访问临界资源的不同区域此时不会出现数据不一致等问题。 1.2 信号量的概念 信号量信号灯本质是一个计数器是描述临界资源中资源数目的计数器信号量能够更细粒度的对临界资源进行管理。 每个执行流在进入临界区之前都应该先申请信号量申请成功就有了操作特点的临界资源的权限当操作完毕后就应该释放信号量。 信号量的PV操作 P操作我们将申请信号量称为P操作申请信号量的本质就是申请获得临界资源中某块资源的使用权限当申请成功时临界资源中资源的数目应该减一因此P操作的本质就是让计数器减一。V操作我们将释放信号量称为V操作释放信号量的本质就是归还临界资源中某块资源的使用权限当释放成功时临界资源中资源的数目就应该加一因此V操作的本质就是让计数器加一。 PV操作必须是原子操作 多个执行流为了访问临界资源会竞争式的申请信号量因此信号量是会被多个执行流同时访问的也就是说信号量本质也是临界资源。 但信号量本质就是用于保护临界资源的我们不可能再用信号量去保护信号量所以信号量的PV操作必须是原子操作。 注意 内存当中变量的、–操作并不是原子操作因此信号量不可能只是简单的对一个全局变量进行、–操作。 申请信号量失败被挂起等待 当执行流在申请信号量时可能此时信号量的值为0也就是说信号量描述的临界资源已经全部被申请了此时该执行流就应该在该信号量的等待队列当中进行等待直到有信号量被释放时再被唤醒。 注意 信号量的本质是计数器但不意味着只有计数器信号量还包括一个等待队列。 1.3 信号量函数 初始化信号量 初始化信号量的函数叫做sem_init int sem_init(sem_t *sem, int pshared, unsigned int value);参数说明 sem需要初始化的信号量。pshared传入0值表示线程间共享传入非零值表示进程间共享。value信号量的初始值计数器的初始值。 返回值说明 初始化信号量成功返回0失败返回-1。 注意 POSIX信号量和System V信号量作用相同都是用于同步操作达到无冲突的访问共享资源目的但POSIX信号量可以用于线程间同步。 销毁信号量 销毁信号量的函数叫做sem_destroy int sem_destroy(sem_t *sem);参数说明 sem需要销毁的信号量。 返回值说明 销毁信号量成功返回0失败返回-1。 等待信号量申请信号量 等待信号量的函数叫做sem_wait int sem_wait(sem_t *sem);参数说明 sem需要等待的信号量。 返回值说明 等待信号量成功返回0信号量的值减一。 等待信号量失败返回-1信号量的值保持不变。 发布信号量释放信号量 发布信号量的函数叫做sem_post int sem_post(sem_t *sem);参数说明 sem需要发布的信号量。 返回值说明 发布信号量成功返回0信号量的值加一。发布信号量失败返回-1信号量的值保持不变。 2. 二元信号量模拟实现互斥功能 信号量本质是一个计数器如果将信号量的初始值设置为1那么此时该信号量叫做二元信号量。 信号量的初始值为1说明信号量所描述的临界资源只有一份此时信号量的作用基本等价于互斥锁。 下面我们实现一个多线程抢票系统其中我们用二元信号量模拟实现多线程互斥。 我们在主线程当中创建四个新线程让这四个新线程执行抢票逻辑并且每次抢完票后打印输出此时剩余的票数其中我们用全局变量tickets记录当前剩余的票数此时tickets是会被多个执行流同时访问的临界资源在下面的代码中我们并没有对tickets进行任何保护操作。 #include iostream #include string #include unistd.h #include pthread.hint tickets 2000; void* TicketGrabbing(void* arg) {std::string name (char*)arg;while (true){if (tickets 0){usleep(1000);std::cout name get a ticket, tickets left: --tickets std::endl;}else{break;}}std::cout name quit... std::endl;pthread_exit((void*)0); }int main() {pthread_t tid1, tid2, tid3, tid4;pthread_create(tid1, nullptr, TicketGrabbing, (void*)thread 1);pthread_create(tid2, nullptr, TicketGrabbing, (void*)thread 2);pthread_create(tid3, nullptr, TicketGrabbing, (void*)thread 3);pthread_create(tid4, nullptr, TicketGrabbing, (void*)thread 4);pthread_join(tid1, nullptr);pthread_join(tid2, nullptr);pthread_join(tid3, nullptr);pthread_join(tid4, nullptr);return 0; } 运行代码后可以看到线程打印输出剩余票数时出现了票数剩余为负数的情况这是不符合我们预期的。 下面我们在抢票逻辑当中加入二元信号量让每个线程在访问全局变量tickets之前先申请信号量访问完毕后再释放信号量此时二元信号量就达到了互斥的效果。 #include iostream #include string #include unistd.h #include pthread.h #include semaphore.hclass Sem{ public:Sem(int num){sem_init(_sem, 0, num);}~Sem(){sem_destroy(_sem);}void P(){sem_wait(_sem);}void V(){sem_post(_sem);} private:sem_t _sem; };Sem sem(1); //二元信号量 int tickets 2000; void* TicketGrabbing(void* arg) {std::string name (char*)arg;while (true){sem.P();if (tickets 0){usleep(1000);std::cout name get a ticket, tickets left: --tickets std::endl;sem.V();}else{sem.V();break;}}std::cout name quit... std::endl;pthread_exit((void*)0); }int main() {pthread_t tid1, tid2, tid3, tid4;pthread_create(tid1, nullptr, TicketGrabbing, (void*)thread 1);pthread_create(tid2, nullptr, TicketGrabbing, (void*)thread 2);pthread_create(tid3, nullptr, TicketGrabbing, (void*)thread 3);pthread_create(tid4, nullptr, TicketGrabbing, (void*)thread 4);pthread_join(tid1, nullptr);pthread_join(tid2, nullptr);pthread_join(tid3, nullptr);pthread_join(tid4, nullptr);return 0; }运行代码后就不会出现剩余票数为负的情况了因为此时同一时刻只会有一个执行流对全局变量tickets进行访问不会出现数据不一致的问题。 3. 基于环形队列的生产消费模型 3.1 空间资源和数据资源 生产者关注的是空间资源消费者关注的是数据资源 对于生产者和消费者来说它们关注的资源是不同的 生产者关注的是环形队列当中是否有空间blank只要有空间生产者就可以进行生产。消费者关注的是环形队列当中是否有数据data只要有数据消费者就可以进行消费。 blank_sem和data_sem的初始值设置 现在我们用信号量来描述环形队列当中的空间资源blank_sem和数据资源data_sem在我们初始信号量时给它们设置的初始值是不同的 blank_sem的初始值我们应该设置为环形队列的容量因为刚开始时环形队列当中全是空间。data_sem的初始值我们应该设置为0因为刚开始时环形队列当中没有数据。 3.2 生产者和消费者申请和释放资源 生产者申请空间资源释放数据资源 对于生产者来说生产者每次生产数据前都需要先申请blank_sem 如果blank_sem的值不为0则信号量申请成功此时生产者可以进行生产操作。如果blank_sem的值为0则信号量申请失败此时生产者需要在blank_sem的等待队列下进行阻塞等待直到环形队列当中有新的空间后再被唤醒。 当生产者生产完数据后应该释放data_sem 虽然生产者在进行生产前是对blank_sem进行的P操作但是当生产者生产完数据应该对data_sem进行V操作而不是blank_sem。生产者在生产数据前申请到的是blank位置当生产者生产完数据后该位置当中存储的是生产者生产的数据在该数据被消费者消费之前该位置不再是blank位置而应该是data位置。当生产者生产完数据后意味着环形队列当中多了一个data位置因此我们应该对data_sem进行V操作。 消费者申请数据资源释放空间资源 对于消费者来说消费者每次消费数据前都需要先申请data_sem 如果data_sem的值不为0则信号量申请成功此时消费者可以进行消费操作。如果data_sem的值为0则信号量申请失败此时消费者需要在data_sem的等待队列下进行阻塞等待直到环形队列当中有新的数据后再被唤醒。 当消费者消费完数据后应该释放blank_sem 虽然消费者在进行消费前是对data_sem进行的P操作但是当消费者消费完数据应该对blank_sem进行V操作而不是data_sem。消费者在消费数据前申请到的是data位置当消费者消费完数据后该位置当中的数据已经被消费过了再次被消费就没有意义了为了让生产者后续可以在该位置生产新的数据我们应该将该位置算作blank位置而不是data位置。当消费者消费完数据后意味着环形队列当中多了一个blank位置因此我们应该对blank_sem进行V操作。 3.3 必须遵守的两个规则 在基于环形队列的生产者和消费者模型当中生产者和消费者必须遵守如下两个规则 第一个规则生产者和消费者不能对同一个位置进行访问。 生产者和消费者在访问环形队列时 如果生产者和消费者访问的是环形队列当中的同一个位置那么此时生产者和消费者就相当于同时对这一块临界资源进行了访问这当然是不允许的。而如果生产者和消费者访问的是环形队列当中的不同位置那么此时生产者和消费者是可以同时进行生产和消费的此时不会出现数据不一致等问题。 第二个规则无论是生产者还是消费者都不应该将对方套一个圈以上。 生产者从消费者的位置开始一直按顺时针方向进行生产如果生产者生产的速度比消费者消费的速度快那么当生产者绕着消费者生产了一圈数据后再次遇到消费者此时生产者就不应该再继续生产了因为再生产就会覆盖还未被消费者消费的数据。消费者从生产者的位置开始一直按顺时针方向进行消费如果消费者消费的速度比生产者生产的速度快那么当消费者绕着生产者消费了一圈数据后再次遇到生产者此时消费者就不应该再继续消费了因为再消费就会消费到缓冲区中保存的废弃数据。 3.4 代码实现 #pragma once#include iostream #include unistd.h #include pthread.h #include semaphore.h #include vector#define NUM 8templateclass T class RingQueue { private://P操作void P(sem_t s){sem_wait(s);}//V操作void V(sem_t s){sem_post(s);} public:RingQueue(int cap NUM): _cap(cap), _p_pos(0), _c_pos(0){_q.resize(_cap);sem_init(_blank_sem, 0, _cap); //blank_sem初始值设置为环形队列的容量sem_init(_data_sem, 0, 0); //data_sem初始值设置为0}~RingQueue(){sem_destroy(_blank_sem);sem_destroy(_data_sem);}//向环形队列插入数据生产者调用void Push(const T data){P(_blank_sem); //生产者关注空间资源_q[_p_pos] data;V(_data_sem); //生产//更新下一次生产的位置_p_pos;_p_pos % _cap;}//从环形队列获取数据消费者调用void Pop(T data){P(_data_sem); //消费者关注数据资源data _q[_c_pos];V(_blank_sem);//更新下一次消费的位置_c_pos;_c_pos % _cap;} private:std::vectorT _q; //环形队列int _cap; //环形队列的容量上限int _p_pos; //生产位置int _c_pos; //消费位置sem_t _blank_sem; //描述空间资源sem_t _data_sem; //描述数据资源 }; 相关说明 当不设置环形队列的大小时我们默认将环形队列的容量上限设置为8。代码中的RingQueue是用vector实现的生产者每次生产的数据放到vector下标为p_pos的位置消费者每次消费的数据来源于vector下标为c_pos的位置。生产者每次生产数据后p_pos都会进行标记下一次生产数据的存放位置后的下标会与环形队列的容量进行取模运算实现“环形”的效果。消费者每次消费数据后c_pos都会进行标记下一次消费数据的来源位置后的下标会与环形队列的容量进行取模运算实现“环形”的效果。p_pos只会由生产者线程进行更新c_pos只会由消费者线程进行更新对这两个变量访问时不需要进行保护因此代码中将p_pos和c_pos的更新放到了V操作之后就是为了尽量减少临界区的代码。 为了方便理解我们这里实现单生产者、单消费者的生产者消费者模型。于是在主函数我们就只需要创建一个生产者线程和一个消费者线程生产者线程不断生产数据放入环形队列消费者线程不断从环形队列里取出数据进行消费。 #include RingQueue.hppvoid* Producer(void* arg) {RingQueueint* rq (RingQueueint*)arg;while (true){sleep(1);int data rand() % 100 1;rq-Push(data);std::cout Producer: data std::endl;} } void* Consumer(void* arg) {RingQueueint* rq (RingQueueint*)arg;while (true){sleep(1);int data 0;rq-Pop(data);std::cout Consumer: data std::endl;} } int main() {srand((unsigned int)time(nullptr));pthread_t producer, consumer;RingQueueint* rq new RingQueueint;pthread_create(producer, nullptr, Producer, rq);pthread_create(consumer, nullptr, Consumer, rq);pthread_join(producer, nullptr);pthread_join(consumer, nullptr);delete rq;return 0; } 相关说明 环形队列要让生产者线程向队列中Push数据让消费者线程从队列中Pop数据因此这个环形队列必须要让这两个线程同时看到所以我们在创建生产者线程和消费者线程时需要将环形队列作为线程执行例程的参数进行传入。代码中生产者生产数据就是将获取到的随机数Push到环形队列而消费者就是从环形队列Pop数据为了便于观察我们可以将生产者生产的数据和消费者消费的数据进行打印输出。 生产者消费者步调一致 如果想步调不一致只需要把sleep删掉就可以实现 3.5 信号量保护环形队列的原理 在blank_sem和data_sem两个信号量的保护后该环形队列中不可能会出现数据不一致的问题。 因为只有当生产者和消费者指向同一个位置并访问时才会导致数据不一致的问题而此时生产者和消费者在对环形队列进行写入或读取数据时只有两种情况会指向同一个位置 环形队列为空时。环形队列为满时。 但是在这两种情况下生产者和消费者不会同时对环形队列进行访问 当环形队列为空的时消费者一定不能进行消费因为此时数据资源为0。当环形队列为满的时生产者一定不能进行生产因为此时空间资源为0。 也就是说当环形队列为空和满时我们已经通过信号量保证了生产者和消费者的串行化过程。而除了这两种情况之外生产者和消费者指向的都不是同一个位置因此该环形队列当中不可能会出现数据不一致的问题。并且大部分情况下生产者和消费者指向并不是同一个位置因此大部分情况下该环形队列可以让生产者和消费者并发的执行
http://www.hkea.cn/news/14282782/

相关文章:

  • 莆田外贸网站建设推广计算机网站开发毕业设计论文开题报告
  • 怎么做的网站收录快网站制作企业有哪些
  • 网站制作教程谁的好公司网站怎么建立优化体系
  • 松山湖网站建设公司在汕头的网络公司有哪些
  • 视频直播网站网页设计案例
  • 前端响应式网站wordpress国主题公园
  • 微信手机网站开发苏州注册公司好快记财务
  • 设计网站如何推广方案织梦猫网站模板
  • 品牌网站策划书百度seo优
  • 山西省财政厅门户网站三基建设网站的汉化包怎么做
  • 网站官网认证加v怎么做wordpress手机移动版
  • 网站制作宣传洛阳做网站排名
  • 网站开发人员没有按照设计开发网站开发需要什么专业
  • 做网站软件定制开发中铁建设集团门户网门户
  • 专门做外卖的网站深圳百度
  • 小程序 手机网站在工商网站上怎么做电话的变更
  • 网络建站流程网页制作自我介绍源代码
  • html网站分页怎么做的学网站建设需要什么软件有哪些
  • 自己做的网站如何推广如何利用网站做产品推广
  • 做企业网站需要购什么简单房地产网站
  • 做服装必须看的十大网站网络营销是以什么为基础
  • 用dw做网站郑州本地seo顾问
  • 文山州建设局网站html制作个人简历
  • 网站头部固定网站建设 中企动力东莞后台管理
  • 手机网站与pc网站同步微博短网址生成
  • 滁州seo网站推广wordpress替换文字
  • 商务电商网站建设宣城市网站建设
  • 莱芜信息招聘平台seo网站优化代码
  • 苏州手机网站搭建一个网站需要多少钱
  • 众筹网站搭建请别人做网站注意事项