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

我想弄个自己的卖货网站怎样做一级a做爰片拍网站

我想弄个自己的卖货网站怎样做,一级a做爰片拍网站,凡科小程序教程,全景720效果图是什么软件信号量 一、POSIX信号量1、信号量的原理2、信号量的概念#xff08;1#xff09;PV操作必须是原子操作#xff08;2#xff09;申请信号量失败被挂起等待 3、信号量函数4、销毁信号量5、等待信号量#xff08;申请信号量#xff09;6、发布信号量#xff08;释放信号量1PV操作必须是原子操作2申请信号量失败被挂起等待 3、信号量函数4、销毁信号量5、等待信号量申请信号量6、发布信号量释放信号量 二、二元信号量模拟实现互斥功能1、负数情况2、引入二元信号量 三、基于环形队列的生产消费模型1、空间资源和数据资源1生产者和消费者关注的不同资源2blank_sem和data_sem的初始值设置3生产者和消费者申请和释放资源i、生产者申请空间资源释放数据资源ii、消费者申请数据资源释放空间资源 2、两个规则1生产者和消费者不能对同一个位置进行访问2无论是生产者还是消费者都不应该将对方套一个圈以上 3、利用代码进行讲解1消费者和生产者步调一致2生产者生产的快消费者消费的慢3生产者生产的慢消费者消费的快 四、信号量保护环形队列的原理 一、POSIX信号量 1、信号量的原理 我们将可能会被多个执行流同时访问的资源叫做临界资源临界资源需要进行保护否则会出现数据不一致等问题。当我们仅用一个互斥锁对临界资源进行保护时相当于我们将这块临界资源看作一个整体同一时刻只允许一个执行流对这块临界资源进行访问。但实际我们可以将这块临界资源再分割为多个区域当多个执行流需要访问临界资源时如果这些执行流访问的是临界资源的不同区域那么我们可以让这些执行流同时访问临界资源的不同区域此时不会出现数据不一致等问题。 2、信号量的概念 信号量信号灯本质是一个计数器是描述临界资源中资源数目的计数器信号量能够更细粒度的对临界资源进行管理。 每个执行流在进入临界区之前都应该先申请信号量申请成功就有了操作特点的临界资源的权限当操作完毕后就应该释放信号量。 信号量的PV操作: P操作我们将申请信号量称为P操作申请信号量的本质就是申请获得临界资源中某块资源的使用权限当申请成功时临界资源中资源的数目应该减一因此P操作的本质就是让计数器减一。V操作我们将释放信号量称为V操作释放信号量的本质就是归还临界资源中某块资源的使用权限当释放成功时临界资源中资源的数目就应该加一因此V操作的本质就是让计数器加一。 1PV操作必须是原子操作 多个执行流为了访问临界资源会竞争式的申请信号量因此信号量是会被多个执行流同时访问的也就是说信号量本质也是临界资源。 但信号量本质就是用于保护临界资源的我们不可能再用信号量去保护信号量所以信号量的PV操作必须是原子操作。 2申请信号量失败被挂起等待 当执行流在申请信号量时可能此时信号量的值为0也就是说信号量描述的临界资源已经全部被申请了此时该执行流就应该在该信号量的等待队列当中进行等待直到有信号量被释放时再被唤醒。信号量的本质是计数器但不意味着只有计数器信号量还包括一个等待队列。 3、信号量函数 初始化信号量的函数叫做sem_init该函数的函数原型如下 int sem_init(sem_t *sem, int pshared, unsigned int value);参数说明 sem需要初始化的信号量。pshared传入0值表示线程间共享传入非零值表示进程间共享。value信号量的初始值计数器的初始值。 返回值 初始化信号量成功返回0失败返回-1。 注意 POSIX信号量和System V信号量作用相同都是用于同步操作达到无冲突的访问共享资源目的但POSIX信号量可以用于线程间同步。 4、销毁信号量 销毁信号量的函数叫做sem_destroy该函数的函数原型如下 int sem_destroy(sem_t *sem);参数说明 sem需要销毁的信号量。 返回值说明 销毁信号量成功返回0失败返回-1。 5、等待信号量申请信号量 等待信号量的函数叫做sem_wait该函数的函数原型如下 int sem_wait(sem_t *sem);参数说明 sem需要等待的信号量。 返回值说明 等待信号量成功返回0信号量的值减一。等待信号量失败返回-1信号量的值保持不变。 6、发布信号量释放信号量 发布信号量的函数叫做sem_post该函数的函数原型如下 int sem_post(sem_t *sem);参数说明 sem需要发布的信号量。 返回值说明 发布信号量成功返回0信号量的值加一。发布信号量失败返回-1信号量的值保持不变。 二、二元信号量模拟实现互斥功能 1、负数情况 信号量本质是一个计数器如果将信号量的初始值设置为1那么此时该信号量叫做二元信号量。 信号量的初始值为1说明信号量所描述的临界资源只有一份此时信号量的作用基本等价于互斥锁。 我们不知道还记得之间写的最初的抢票逻辑吗我们创建四个新线程四个新线程实现抢票但最终是出现负数的情况我们再看一眼下面的代码 #include iostream #include pthread.h #include unistd.h using namespace std; // 临界资源1000张票 int tickets 1000; void* Routine(void* arg) {const char* name (char*)arg;// 抢票while(1){if(tickets 0){// 抢票usleep(10000);printf([%s] get a ticket...left tickets#%d\n, name, --tickets);}else{break;}}cout name exit... endl;pthread_exit((void*)0); } int main() {pthread_t tid1, tid2, tid3, tid4;// 创建四个新线程pthread_create(tid1, NULL, Routine, (void*)thread 1);pthread_create(tid2, NULL, Routine, (void*)thread 2);pthread_create(tid3, NULL, Routine, (void*)thread 3);pthread_create(tid4, NULL, Routine, (void*)thread 4);// 退出pthread_join(tid1, NULL);pthread_join(tid2, NULL);pthread_join(tid3, NULL);pthread_join(tid4, NULL);return 0; }我们发现是有负数的这显然不符合我们预期的。 2、引入二元信号量 下面我们在抢票逻辑当中加入二元信号量让每个线程在访问全局变量tickets之前先申请信号量访问完毕后再释放信号量此时二元信号量就达到了互斥的效果。 #include iostream #include pthread.h #include unistd.h #include semaphore.h #include string // 实现一个Sem类函数 class Sem { private:sem_t _sem; public:// 构造函数Sem(int num){sem_init(_sem, 0, num);}// 析构函数~Sem(){sem_destroy(_sem);}// P操作void P(){sem_wait(_sem);}// V操作void V(){sem_post(_sem);} }; // 二原信号量 Sem sem(1); int tickets 1000; void* TicketGrabbge(void* arg) {// 抢票std::string Name (char*)arg;while(1){sem.P(); // 等待信号量if(tickets 0){// 出票usleep(10000);std::cout [ Name ] get a tickets# --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, TicketGrabbge, (void*)thread 1);pthread_create(tid2, nullptr, TicketGrabbge, (void*)thread 2);pthread_create(tid3, nullptr, TicketGrabbge, (void*)thread 3);pthread_create(tid4, nullptr, TicketGrabbge, (void*)thread 4);// 线程等待pthread_join(tid1, nullptr);pthread_join(tid2, nullptr);pthread_join(tid3, nullptr);pthread_join(tid4, nullptr);return 0; }运行代码后就不会出现剩余票数为负的情况了因为此时同一时刻只会有一个执行流对全局变量tickets进行访问不会出现数据不一致的问题。 三、基于环形队列的生产消费模型 1、空间资源和数据资源 1生产者和消费者关注的不同资源 生产者关注的是空间资源消费者关注的是数据资源 对于生产者和消费者来说它们关注的资源是不同的 生产者关注的是环形队列当中是否有空间blank只要有空间生产者就可以进行生产。消费者关注的是环形队列当中是否有数据data只要有数据消费者就可以进行消费。 2blank_sem和data_sem的初始值设置 现在我们用信号量来描述环形队列当中的空间资源blank_sem和数据资源data_sem在我们初始信号量时给它们设置的初始值是不同的 blank_sem的初始值我们应该设置为环形队列的容量因为刚开始时环形队列当中全是空间。data_sem的初始值我们应该设置为0因为刚开始时环形队列当中没有数据。 3生产者和消费者申请和释放资源 i、生产者申请空间资源释放数据资源 对于生产者来说生产者每次生产数据前都需要先申请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操作。 ii、消费者申请数据资源释放空间资源 对于消费者来说消费者每次消费数据前都需要先申请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操作。 2、两个规则 1生产者和消费者不能对同一个位置进行访问 如果生产者和消费者访问的是环形队列当中的同一个位置那么此时生产者和消费者就相当于同时对这一块临界资源进行了访问这当然是不允许的。而如果生产者和消费者访问的是环形队列当中的不同位置那么此时生产者和消费者是可以同时进行生产和消费的此时不会出现数据不一致等问题。 2无论是生产者还是消费者都不应该将对方套一个圈以上 生产者从消费者的位置开始一直按顺时针方向进行生产如果生产者生产的速度比消费者消费的速度快那么当生产者绕着消费者生产了一圈数据后再次遇到消费者此时生产者就不应该再继续生产了因为再生产就会覆盖还未被消费者消费的数据。同理消费者从生产者的位置开始一直按顺时针方向进行消费如果消费者消费的速度比生产者生产的速度快那么当消费者绕着生产者消费了一圈数据后再次遇到生产者此时消费者就不应该再继续消费了因为再消费就会消费到缓冲区中保存的废弃数据。 3、利用代码进行讲解 signal.hpp: #pragma once #include iostream #include unistd.h #include pthread.h #include semaphore.h #include vector #define NUM 10 templateclass T class RingQueue { private:std::vectorT _q; // 循环队列int _capacity; // 循环队列的容量int _p_pos; // 生产位置int _c_pos; // 消费位置sem_t _blank_sem; // 描述空间资源sem_t _data_sem; // 描述数据资源 private:// P操作 -- 等待void P(sem_t s){sem_wait(s);}// V操作 -- 传递void V(sem_t s){sem_post(s);} public:// 构造函数RingQueue(int cap NUM):_capacity(cap),_p_pos(0),_c_pos(0){_q.resize(_capacity);sem_init(_blank_sem, 0, _capacity); // 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; // 环形队列中的相对应位置用data填入V(_data_sem); // 向数据资源解锁!即生产资源// 更新下一次插入的位置_p_pos;_p_pos % _capacity;}// 消费者void Pop(T data){P(_data_sem); // 向数据资源加锁data _q[_c_pos]; // 拿到消费位置的数据V(_blank_sem); // 空间资源的解锁即开始将空间资源进行增加空间// 更新下一次弹出的位置_c_pos;_c_pos % _capacity;} };当不设置环形队列的大小时我们默认将环形队列的容量上限设置为10。代码中的RingQueue是用vector实现的生产者每次生产的数据放到vector下标为p_pos的位置消费者每次消费的数据来源于vector下标为c_pos的位置。生产者每次生产数据后p_pos都会进行标记下一次生产数据的存放位置后的下标会与环形队列的容量进行取模运算实现“环形”的效果。消费者每次消费数据后c_pos都会进行标记下一次消费数据的来源位置后的下标会与环形队列的容量进行取模运算实现“环形”的效果。p_pos只会由生产者线程进行更新c_pos只会由消费者线程进行更新对这两个变量访问时不需要进行保护因此代码中将p_pos和c_pos的更新放到了V操作之后就是为了尽量减少临界区的代码。 我们这里设置两个线程一个是消费者线程另一个是生产者线程生产者负责生产数据到环形队列中消费者负责在环形队列中获取数据 main.cc: #include signal.hppvoid* Productor(void* arg) {RingQueueint* Name (RingQueueint*)arg;while(1){sleep(1);int data rand() % 100 1;Name-Push(data);std::cout Productor### data std::endl;} }void* Consumer(void* arg) {RingQueueint* Name (RingQueueint*)arg;while(1){sleep(1);int data 0;Name-Pop(data);std::cout Consumer### data std::endl;} }int main() {srand((unsigned int)time(nullptr));pthread_t tid1, tid2;// 创造两个新线程RingQueueint* rq new RingQueueint;pthread_create(tid1, nullptr, Productor, rq);pthread_create(tid2, nullptr, Consumer, rq);// 线程等待pthread_join(tid1, nullptr);pthread_join(tid2, nullptr);delete rq; // 防止内存泄漏return 0; }说明 环形队列要让生产者线程向队列中Push数据让消费者线程从队列中Pop数据因此这个环形队列必须要让这两个线程同时看到所以我们在创建生产者线程和消费者线程时需要将环形队列作为线程执行例程的参数进行传入。代码中生产者生产数据就是将获取到的随机数Push到环形队列而消费者就是从环形队列Pop数据为了便于观察我们可以将生产者生产的数据和消费者消费的数据进行打印输出。 1消费者和生产者步调一致 我们上面的代码就是消费者和消费者步调一致我们进行运行代码并进行打印一看 2生产者生产的快消费者消费的慢 生产者不停的进行生产而消费者每隔一秒进行消费。 void* Productor(void* arg) {RingQueueint* Name (RingQueueint*)arg;while(1){int data rand() % 100 1;Name-Push(data);std::cout Productor### data std::endl;} }void* Consumer(void* arg) {RingQueueint* Name (RingQueueint*)arg;while(1){sleep(1);int data 0;Name-Pop(data);std::cout Consumer### data std::endl;} }此时由于生产者生产的很快运行代码后一瞬间生产者就将环形队列打满了此时生产者想要再进行生产但空间资源已经满了于是生产者只能在blank_sem的等待队列下进行阻塞等待直到由消费者消费完一个数据后对blank_sem进行了V操作生产者才会被唤醒进而继续进行生产。 但由于生产者的生产速度很快生产者生产完一个数据后又会进行等待因此后续生产者和消费者的步调又变成一致的了。 3生产者生产的慢消费者消费的快 生产者每隔一秒进行生产而消费者不停的进行消费。 void* Productor(void* arg) {RingQueueint* Name (RingQueueint*)arg;while(1){sleep(1);int data rand() % 100 1;Name-Push(data);std::cout Productor### data std::endl;} }void* Consumer(void* arg) {RingQueueint* Name (RingQueueint*)arg;while(1){int data 0;Name-Pop(data);std::cout Consumer### data std::endl;} }虽然消费者消费的很快但一开始环形队列当中的数据资源为0因此消费者只能在data_sem的等待队列下进行阻塞等待直到生产者生产完一个数据后对data_sem进行了V操作消费者才会被唤醒进而进行消费。 但由于消费者的消费速度很快消费者消费完一个数据后又会进行等待因此后续生产者和消费者的步调又变成一致的了。 四、信号量保护环形队列的原理 在blank_sem和data_sem两个信号量的保护后该环形队列中不可能会出现数据不一致的问题。 因为只有当生产者和消费者指向同一个位置并访问时才会导致数据不一致的问题而此时生产者和消费者在对环形队列进行写入或读取数据时只有两种情况会指向同一个位置 环形队列为空时。环形队列为满时。 但是在这两种情况下生产者和消费者不会同时对环形队列进行访问 当环形队列为空的时消费者一定不能进行消费因为此时数据资源为0。当环形队列为满的时生产者一定不能进行生产因为此时空间资源为0。 当环形队列为空和满时我们已经通过信号量保证了生产者和消费者的串行化过程。而除了这两种情况之外生产者和消费者指向的都不是同一个位置因此该环形队列当中不可能会出现数据不一致的问题。并且大部分情况下生产者和消费者指向并不是同一个位置因此大部分情况下该环形队列可以让生产者和消费者并发的执行。
http://www.zqtcl.cn/news/549894/

相关文章:

  • 教育网站 php网络服务公司
  • net域名做网站怎么样建站公司 转型经验
  • 赣州网站建设哪家公司好上海市建设安全协会网站
  • 网站排名优化软件有哪些西宁网站建设官网
  • 支付宝手机网站签约迪庆公司网站开发方法
  • 唐山网站关键词优化网站开发公司推荐
  • 福建响应式网站制作市工商局网站建设情况
  • 深圳网站运营托管罗伯特清崎说的网络营销是什么
  • 太仓市质监站网址百度关键字推广费用
  • 为您打造高端品牌网站pageadmin wordpress
  • 中小型网站建设的基本流程简约网站欣赏
  • 设备上哪个网站做外贸推广网络服务类型及其所采用的网络协议
  • 学习前端开发的网站动漫设计属于什么大类
  • 十堰秦楚网 十堰新闻门户网站报修网站模板
  • 家居小程序源码下载自动seo系统
  • 动态效果的网站建设技术老闵行是指哪里
  • 电商网站开发面临的技术问题做闪图的网站
  • 怎么查看网站开发语言的类型东莞哪些地方是风险区
  • 不用购买域名做网站广州网站建设培训学校
  • 城市轨道建设规范下载网站古网站典模板
  • 关于实验室建设的英文网站深圳企业网站制作公司怎样
  • wordpress全站背景音乐中山网站搜索排名
  • 搭建网站的过程透明主题wordpress
  • 丰台网站建设公司电话深圳微信商城网站设计公司
  • 做淘宝要用的网站吗上海微信网站
  • 佛山高端网站制作公司wordpress 发送邮件插件
  • 类似站酷的设计类网站网站建设需要待摊吗
  • 用php做视频网站在学做网站还不知道买什么好
  • wordpress培训类网站网站建设 好
  • 网站开发需要2个月吗网站建设案例精粹