目录
1.信号量的原理
资源计数器+PCB等待队列
资源计数器:执行流获取信号量,获取成功,信号量减一操作,获取失败,执行流放进PCB等待队列,执行流释放信号量成功后,计数器加一操作
条件变量信号模型
信号量模型
总结:对比发现,条件变量是先获取互斥锁,拿到锁后判断资源是否符合条件,符合条件就继续执行,不符合条件就解锁放进PCB等待队列,在合适时机加锁唤醒执行。信号量是执行流先获取信号量,根据信号量的资源计数器判断是否符合要求,不符合就放入等待队列,符合就继续执行,减轻了抢锁压力。
2.信号量的接口
2.1初始化接口
int sem_init(sem_t *sem,int pshared,unsigned int value);
参数 :sem:信号量,sem_t是信号量类型
pshared:该信号量是用于线程间还是进程间
0,用于线程间,全局变量
非0:用于进程间,将信号量用到的资源在共享内存中进行开辟
value:资源的个数,初始化信号量计数器的值
2.2等待接口
int sem_init(sem_t *sem);
1. 对计数器进行减一操作
2.判断资源计数器的值是否小于0
是:阻塞等待,将执行流放入PCB等待队列
否:接口返回
2.3释放接口
int sem_post(sem_t *sem);
会对计数器加一操作,判断资源计数器的值是否小于0,小于0,通知PCB等待队列。不小于0,不通知PCB等待队列,因为没有线程在等待。
2.4销毁接口
int sem_destroy(sem_t *sem);
销毁信号量
3.线程池
3.1使用场景
线程在创建完成之后,只能执行一个线程入口函数,后边就没办法修改,所以线程入口函数的代码就没发改变了,所以线程池就是在生产者消费者模型的基础上改进,将队列中存储的数据替换成数据和处理数据的方法,多个线程可以对数据和方法读取处理。
3.2原理
线程安全的队列+多个线程
1.线程安全的队列
线程安全:互斥和同步
队列:先进先出
元素:处理数据的方法
2.多个线程
3.3代码实现
#include<stdio.h> #include<queue> #include<pthread.h> #include<unistd.h> using namespace std; typedef void (*Handler)(int data); //往线程队列中存的数据格式 class QueueData{ public: QueueData(){ } QueueData(int data,Handler handler){ _data=data; handler_=handler; } void run(){ handler_(_data); } private: int _data; Handler handler_; }; void DealData(int data){ printf("data = %d\n",data); } //线程池 class ThreadPool{ public: ThreadPool(int cap,int thread_count_){ _capcity=cap; pthread_mutex_init(&g_lock,NULL); pthread_cond_init(&cons_cond_,NULL); pthread_cond_init(&con,NULL); thread_count=thread_count_; flag_=0; } ~ThreadPool(){ pthread_mutex_destroy(&g_lock); pthread_cond_destroy(&cons_cond_); pthread_cond_destroy(&con); } int Onit(){ int cnt=0; for(int i=0;i<thread_count;i++){ pthread_t tid; int ret=pthread_create(&tid,NULL,ThreadPoolStart,(void*)this); if(ret<0){ cnt++; perror("pthread_create"); } } thread_count-=cnt; if(thread_count<=0){ return -1; }else{ return 0; } } //线程入口函数 static void* ThreadPoolStart(void* arg){ pthread_detach(pthread_self()); ThreadPool* tp=(ThreadPool*)arg; while(1){ pthread_mutex_lock(&tp->g_lock); while(tp->que_.empty()){ if(tp->flag_){ tp->thread_count--; pthread_mutex_unlock(&tp->g_lock); pthread_exit(NULL); } pthread_cond_wait(&tp->cons_cond_,&tp->g_lock); } QueueData* _qd=new QueueData(); tp->Pop(_qd); pthread_mutex_unlock(&tp->g_lock); pthread_cond_signal(&tp->con); _qd->run(); } } //队列中存数据 void Push(QueueData data){ pthread_mutex_lock(&g_lock); while(que_.size()>=_capcity){ while(flag_){ pthread_mutex_unlock(&g_lock); return; } pthread_cond_wait(&con,&g_lock); } que_.push(data); pthread_mutex_unlock(&g_lock); pthread_cond_signal(&cons_cond_); } //从队列中拿数据 void Pop(QueueData* qd){ *qd = que_.front(); que_.pop(); } void pthread_exit_(){ flag_=1; while(thread_count>0){ pthread_cond_signal(&cons_cond_); } } private: queue<QueueData> que_; size_t _capcity; pthread_mutex_t g_lock; pthread_cond_t cons_cond_; pthread_cond_t con; int thread_count; int flag_; }; int main (){ ThreadPool* tp=new ThreadPool(1,1); if(tp==NULL){ printf("create threadpool fail"); } if(tp->Onit()<0){ printf("create thread fail"); return 0; } for(int i=0;i<10000;i++){ QueueData qd(i,DealData); tp->Push(qd); } tp->pthread_exit_(); delete tp; return 0; }