校园网站建设的作用,wordpress后台缓慢,做网站去哪里找广告主,莱芜网站优化团队✨✨ 欢迎大家来到贝蒂大讲堂✨✨ #x1f388;#x1f388;养成好习惯#xff0c;先赞后看哦~#x1f388;#x1f388; 所属专栏#xff1a;Linux学习 贝蒂的主页#xff1a;Betty’s blog 1. POSIX 信号量
1.1 信号量的概念
为了解决多执行流访问临界区#xff0c… ✨✨ 欢迎大家来到贝蒂大讲堂✨✨ 养成好习惯先赞后看哦~ 所属专栏Linux学习 贝蒂的主页Betty’s blog 1. POSIX 信号量
1.1 信号量的概念
为了解决多执行流访问临界区造成数据不一致等问题我们除了使用互斥锁外我们还可以使用一种 POSIX信号量的方法。
当我们运用互斥锁来保护临界资源时意味着我们把这块临界资源视为一个不可分割的整体在同一时刻只准许一个执行流对其进行访问。
其实我们也能将这块临界资源进一步划分成多个区域。当多个执行流有访问临界资源的需求时若让这些执行流同时去访问临界资源的不同区域此时也并不会引发数据不一致等问题。信号量就是基于此的解决方法。
POSIX信号量本质上是一个计数器用于衡量临界资源中的资源数目。它对临界资源内部的资源数进行统计同时操作系统为其提供了一种对临界资源的预定机制。所有执行流在访问临界资源之前必须先申请信号量。 信号量的 PV 操作 P操作我们将申请信号量称为P操作申请信号量的本质就是申请获得临界资源中某块资源的使用权限当申请成功时临界资源中资源的数目应该减一因此P操作的本质就是让计数器减一。V操作我们将释放信号量称为V操作释放信号量的本质就是归还临界资源中某块资源的使用权限当释放成功时临界资源中资源的数目就应该加一因此V操作的本质就是让计数器加一。 并且由于因信号量的 PV 操作同样属于临界资源所以 PV 操作肯定是原子的。
值得注意的是 虽然 POSIX信号量和SystemV信号量作用相同都是用于同步操作但POSIX信号量常用于线程间同步而 SystemV 信号量常用于进程间通信。
1.2 信号量的接口
1.2.1 初始化信号量
我们首先需要使用 sem_init初始化信号量其用法如下 函数接口int sem_init(sem_t *sem, int pshared, unsigned int value);参数 sem需要初始化的信号量。pshared传入0值表示线程间共享传入非零值表示进程间共享。value信号量的初始值计数器的初始值。 返回值初始化信号量成功返回0失败返回-1。 1.2.2 销毁信号量
在使用完信号量之后我们就需要用 sem_destory 对其进行销毁其用法如下 函数接口int sem_destroy(sem_t *sem);参数 sem需要销毁的信号量。 返回值销毁信号量成功返回0失败返回-1。 1.2.3 申请信号量
申请信号量也就是 P 操作我们需要使用 sem_wait函数其用法如下 函数接口int sem_wait(sem_t *sem);参数 sem需要申请的信号量。 返回值申请信号量成功返回0信号量的值减一。申请信号量失败返回-1信号量的值保持不变。如果信号量为 0则该执行流会被阻塞直至信号量大于 0。 1.2.4 释放信号量
释放信号量也就是 V 操作我们需要使用 sem_post函数其用法如下 函数接口int sem_post(sem_t *sem);参数 sem需要释放的信号量。 返回值释放信号量成功返回0信号量的值加一。释放信号量失败返回-1信号量的值保持不变。 如果信号量的初始值为1那么此时信号量所描述的临界资源只有一份这个临界资源也只能同时被一个执行流访问。此时信号量的作用基本等价于互斥锁这种信号量我们称为二元信号量。
比如我们下面可以通过二元信号量实现我们的抢票逻辑
#include iostream
#include cstdio
#include string
#include unistd.h
#include pthread.h
#include semaphore.h
class 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;
};
int tickets 1000;
Sem sem(1);
void *getTickets(void *args)
{uint64_t i (uint64_t)args;char buffer[64] {0};snprintf(buffer, sizeof(buffer), thread %llu, i);while (true){sem.P();if (tickets 0){usleep(1000);std::cout buffer get a tickettickets left: --tickets std::endl;sem.V();}else{sem.V();break;}}std::cout buffer quit ... std::endl;return nullptr;
}
int main()
{pthread_t tids[5];for (uint64_t i 0; i 5; i){pthread_create(tids i, nullptr, getTickets, (void *)i);}for (int i 0; i 5; i){pthread_join(tids[i], nullptr);}return 0;
}2. 生产者消费者模型
2.1 概念
生产者 - 消费者模型是一种经典的多线程或多进程同步模型。它主要用于解决在数据生产和数据消费速度不一致的情况下如何安全、高效地处理数据的问题。
在这个模型中有两类角色生产者和消费者。生产者负责生产数据例如在一个文件读取系统中生产者可能是读取文件内容并将其转换为特定格式数据的线程或进程消费者则负责消费处理生产者生产的数据比如将读取到的数据进行进一步的分析或者存储到数据库中的线程或进程。 利用该模型我们能实现生产者与消费者之间的解耦并且生产者在生产时其它生产者可以获取数据消费者可以处理数据消费者在消费时也是同理一定程度上实现了并发。
2.2 特点
生产者-消费者模型一般具有以下三个特点 三种关系 生产者和生产者互斥关系、消费者和消费者互斥关系、生产者和消费者互斥关系、同步关系。两种角色 生产者和消费者。通常由进程或线程承担一个交易场所 通常指的是内存中的一段缓冲区。 因为容器是能够被多个执行流访问的一个共享资源所以生产者与生产者消费者与消费者生产者与消费者之间是一个互斥关系而我们访问数据一定是生产者先生产消费者再消费所以生产者与消费者之间是一个同步关系。
3. 生产者消费者模型的实现
3.1 基于阻塞队列实现
阻塞队列就是队列的一种但其要求 当队列为空时从队列获取元素的操作将会被阻塞直到队列中放入了元素。当队列满时往队列里存放元素的操作会被阻塞直到有元素从队列中取出。 其中阻塞队列最典型的应用场景实际上就是管道的实现。 首先我们可以先实现 BlockingQueue的框架首先我们需要一个队列 _q 作为成员变量以及表示其容量的 _cap并且因为涉及多执行流访问需要一把互斥锁 _mutex最后我们还需要两个条件变量 _empty与·_full分别表示当我们队列为空时执行消费的执行流需加入 _empty 条件变量与当我们队列为满时执行生产的执行流需加入该条件变量 _full。
#include iostream
#include pthread.h
#include queue
#include unistd.h
const int defaultnum 5;
template class T
class BlockQueue
{bool IsFull(){return _q.size() _cap;}bool IsEmpty(){return _q.empty();}
public:BlockQueue(int cap defaultnum): _cap(cap){pthread_mutex_init(_mutex, nullptr);pthread_cond_init(_full, nullptr);pthread_cond_init(_empty, nullptr);}~BlockQueue(){pthread_mutex_destroy(_mutex);pthread_cond_destroy(_full);pthread_cond_destroy(_empty);}void Push(const Tdata);void Pop(Tdata);
private:std::queueT _q;int _cap;pthread_mutex_t _mutex;pthread_cond_t _full;pthread_cond_t _empty;
};并且我们实现生产 Push与消费 Pop操作也十分简单生产时如果队列为满则加入条件变量 _full 等待没有则正常生产生产完毕后该队列一定有数据这时我们就需要唤醒 _empty条件变量执行消费操作。而消费操作正好对应如果消费时如果队列为空则加入条件变量 _empty 等待否则正常消费消费完毕后该队列一定不为空这时我们就需要唤醒 _full条件变量执行生产操作。并且生产与消费操作都属于临界资源所以需要加锁。
void Push(const Tdata)
{pthread_mutex_lock(_mutex);while(IsFull()){pthread_cond_wait(_full,_mutex);}_q.push(data);pthread_mutex_unlock(_mutex);pthread_cond_signal(_empty);
}
void Pop(Tdata)
{pthread_mutex_lock(_mutex);while(IsEmpty()){pthread_cond_wait(_empty,_mutex);}data_q.front();_q.pop();pthread_mutex_unlock(_mutex);pthread_cond_signal(_full);
}需要注意的是font stylecolor:rgb(28, 31, 35);pthread_cond_wait/font 函数作为让当前执行流进行等待的函数存在调用失败的可能性若调用失败该执行流会继续往后执行。
在多生产者的情形下当消费者消费了一个数据后若使用 font stylecolor:rgb(28, 31, 35);pthread_cond_broadcast/font 函数唤醒多个生产者此时若阻塞队列仅有一个空位且唤醒的生产者与消费者竞争当生产者持续竞争锁成功时就可能出现错误。鉴于此为避免上述情况发生必须让线程被唤醒后再次进行判断以确认是否真正满足生产消费条件所以这里要用 font stylecolor:rgb(28, 31, 35);while/font 进行判断。
最后我们创建多个线程进行对应的生产与消费操作即可。
#include BlockQueue.hpp
#include cstdlib
#include ctime
void *Producer(void *args)
{pthread_detach(pthread_self());BlockQueueint *bq static_castBlockQueueint *(args);while (true){int data rand() % 100 1;bq-Push(data); std::cout Producer: data std::endl;}
}
void *Consumer(void *args)
{pthread_detach(pthread_self());BlockQueueint *bq static_castBlockQueueint *(args);while (true){int data 0;bq-Pop(data); std::cout Consumer: data std::endl;sleep(1);}
}
int main()
{srand((unsigned int)time(nullptr));BlockQueueint *bq new BlockQueueint;for (int i 0; i 5; i){pthread_t tid;pthread_create(tid, nullptr, Producer, bq);}for (int i 0; i 5; i){pthread_t tid;pthread_create(tid, nullptr, Consumer, bq);}while(true);return 0;
}3.2 基于循环队列实现
我们同样也可以通过循环队列来实现生产者消费者模型并且在循环队列不为空或者满的情况下生产者与消费者可以同步执行。并且要求 当生产和消费指向同一个资源的时候只能一个执行流访问。为空的时候由生产者去访问为满的时候由消费者去访问。消费者不能超过生产者。生产者不能把消费者套圈因为这样会导致数据被覆盖。 首先我们可以先实现 RingQueue的框架首先我们可以使用数组来模仿队列 _q 以及表示其容量的 _cap然后用 _p_pos与 _c_pos分别表示生产者与消费者访问数据的下标其中我们需要两个信号量 _blank_sem与·_data_sem分别表示队列未填数据的个数与已填数据的个数并且因为涉及多执行流访问我们最后要用两把互斥锁 _p_mutex与 _c_mutex来保护生产与消费的临界资源。
#pragma once
#include iostream
#include pthread.h
#include vector
#include semaphore.h
#include unistd.h
const int defaultnum 5;
template class T
class RingQueue
{void P(sem_t s){sem_wait(s);}void V(sem_t s){sem_post(s);}void Lock(pthread_mutex_t *mutex){pthread_mutex_lock(mutex);}void UnLock(pthread_mutex_t *mutex){pthread_mutex_unlock(mutex);}public:RingQueue(int cap defaultnum): _cap(cap), _p_pos(0), _c_pos(0){_q.resize(_cap);sem_init(_blank_sem, 0, _cap);sem_init(_data_sem, 0, 0);pthread_mutex_init(_p_mutex, nullptr);pthread_mutex_init(_c_mutex, nullptr);}~RingQueue(){sem_destroy(_blank_sem);sem_destroy(_data_sem);pthread_mutex_destroy(_p_mutex);pthread_mutex_destroy(_c_mutex);}void Push(const T data);void Pop(T data);
private:std::vectorT _q;int _cap;int _p_pos;int _c_pos;sem_t _blank_sem;sem_t _data_sem;pthread_mutex_t _p_mutex;pthread_mutex_t _c_mutex;
};我们实现生产 Push与消费 Pop操作也十分简单生产时如果队列为满那么未填数据个数 _blank_sem为 0该执行流就会被阻塞没有则正常生产。而消费操作正好对应如果消费时如果队列为空那么已填数据个数 _data_sem为 0该执行流就会被阻塞否则就正常消费并且生产与消费操作都属于临界资源所以需要加锁。
void Push(const T data)
{P(_blank_sem);Lock(_p_mutex);_q[_p_pos] data;_p_pos;_p_pos % _cap;UnLock(_p_mutex);V(_data_sem);
}
void Pop(T data)
{P(_data_sem);Lock(_c_mutex);data _q[_c_pos];_c_pos;_c_pos % _cap;UnLock(_c_mutex);V(_blank_sem);
}
文章转载自: http://www.morning.nhlnh.cn.gov.cn.nhlnh.cn http://www.morning.lwtld.cn.gov.cn.lwtld.cn http://www.morning.bpmnc.cn.gov.cn.bpmnc.cn http://www.morning.qznkn.cn.gov.cn.qznkn.cn http://www.morning.fldrg.cn.gov.cn.fldrg.cn http://www.morning.mkpqr.cn.gov.cn.mkpqr.cn http://www.morning.rstrc.cn.gov.cn.rstrc.cn http://www.morning.kpxzq.cn.gov.cn.kpxzq.cn http://www.morning.zdsqb.cn.gov.cn.zdsqb.cn http://www.morning.wpsfc.cn.gov.cn.wpsfc.cn http://www.morning.qmnhw.cn.gov.cn.qmnhw.cn http://www.morning.drtgt.cn.gov.cn.drtgt.cn http://www.morning.cjqcx.cn.gov.cn.cjqcx.cn http://www.morning.ghssm.cn.gov.cn.ghssm.cn http://www.morning.wpqwk.cn.gov.cn.wpqwk.cn http://www.morning.gjqnn.cn.gov.cn.gjqnn.cn http://www.morning.lpskm.cn.gov.cn.lpskm.cn http://www.morning.rfkyb.cn.gov.cn.rfkyb.cn http://www.morning.cgstn.cn.gov.cn.cgstn.cn http://www.morning.jygsq.cn.gov.cn.jygsq.cn http://www.morning.lgsqy.cn.gov.cn.lgsqy.cn http://www.morning.ltrz.cn.gov.cn.ltrz.cn http://www.morning.rfgkf.cn.gov.cn.rfgkf.cn http://www.morning.21r000.cn.gov.cn.21r000.cn http://www.morning.rqsr.cn.gov.cn.rqsr.cn http://www.morning.krwzy.cn.gov.cn.krwzy.cn http://www.morning.btmwd.cn.gov.cn.btmwd.cn http://www.morning.jgzmr.cn.gov.cn.jgzmr.cn http://www.morning.djmdk.cn.gov.cn.djmdk.cn http://www.morning.jwskq.cn.gov.cn.jwskq.cn http://www.morning.hbqhz.cn.gov.cn.hbqhz.cn http://www.morning.kqhlm.cn.gov.cn.kqhlm.cn http://www.morning.sjjtz.cn.gov.cn.sjjtz.cn http://www.morning.bwmm.cn.gov.cn.bwmm.cn http://www.morning.cxlys.cn.gov.cn.cxlys.cn http://www.morning.ylqrc.cn.gov.cn.ylqrc.cn http://www.morning.ckbmz.cn.gov.cn.ckbmz.cn http://www.morning.hghhy.cn.gov.cn.hghhy.cn http://www.morning.rgxf.cn.gov.cn.rgxf.cn http://www.morning.smcfk.cn.gov.cn.smcfk.cn http://www.morning.fkmyq.cn.gov.cn.fkmyq.cn http://www.morning.dkbgg.cn.gov.cn.dkbgg.cn http://www.morning.ckctj.cn.gov.cn.ckctj.cn http://www.morning.xysxj.com.gov.cn.xysxj.com http://www.morning.yrcxg.cn.gov.cn.yrcxg.cn http://www.morning.pyxtn.cn.gov.cn.pyxtn.cn http://www.morning.wmsgt.cn.gov.cn.wmsgt.cn http://www.morning.gcxfh.cn.gov.cn.gcxfh.cn http://www.morning.clbgy.cn.gov.cn.clbgy.cn http://www.morning.nzfjm.cn.gov.cn.nzfjm.cn http://www.morning.lftpl.cn.gov.cn.lftpl.cn http://www.morning.kgrwh.cn.gov.cn.kgrwh.cn http://www.morning.skksz.cn.gov.cn.skksz.cn http://www.morning.bqfpm.cn.gov.cn.bqfpm.cn http://www.morning.seoqun.com.gov.cn.seoqun.com http://www.morning.elmtw.cn.gov.cn.elmtw.cn http://www.morning.lfqtp.cn.gov.cn.lfqtp.cn http://www.morning.mggwr.cn.gov.cn.mggwr.cn http://www.morning.fcwxs.cn.gov.cn.fcwxs.cn http://www.morning.jkdtz.cn.gov.cn.jkdtz.cn http://www.morning.tqklh.cn.gov.cn.tqklh.cn http://www.morning.fkffr.cn.gov.cn.fkffr.cn http://www.morning.nhbhc.cn.gov.cn.nhbhc.cn http://www.morning.skqfx.cn.gov.cn.skqfx.cn http://www.morning.ppqzb.cn.gov.cn.ppqzb.cn http://www.morning.wnpps.cn.gov.cn.wnpps.cn http://www.morning.wmmjw.cn.gov.cn.wmmjw.cn http://www.morning.ldzss.cn.gov.cn.ldzss.cn http://www.morning.clwhf.cn.gov.cn.clwhf.cn http://www.morning.dzqr.cn.gov.cn.dzqr.cn http://www.morning.mqzcn.cn.gov.cn.mqzcn.cn http://www.morning.fglxh.cn.gov.cn.fglxh.cn http://www.morning.flchj.cn.gov.cn.flchj.cn http://www.morning.rkzk.cn.gov.cn.rkzk.cn http://www.morning.qrpx.cn.gov.cn.qrpx.cn http://www.morning.qxbsq.cn.gov.cn.qxbsq.cn http://www.morning.bzfld.cn.gov.cn.bzfld.cn http://www.morning.jwfqq.cn.gov.cn.jwfqq.cn http://www.morning.tnrdz.cn.gov.cn.tnrdz.cn http://www.morning.tqgx.cn.gov.cn.tqgx.cn