linux:线程 POSIX信号量&&线程池
Posted mbf330
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了linux:线程 POSIX信号量&&线程池相关的知识,希望对你有一定的参考价值。
文章目录
POSIX信号量
POSIX信号量和SystemV信号量作用相同,都是用于同步操作,达到无冲突的访问共享资源目的。 但POSIX可以用于线程间同步。
1.POSIX信号量的系统调用函数
头文件:#include<semaphore.h>
(1)初始化信号量
int sem_init(sem_t *sem, int pshared, unsigned int value);
参数:
pshared:0表示线程间共享,非零表示进程间共享。
value:信号量初始值。
(2)销毁信号量
int sem_destroy(sem_t *sem);
(3)等待信号量
P操作,等待信号量,会将信号量的值减1,请求资源。
int sem_wait(sem_t *sem); //P操作
(4)发布信号量
V操作,发布信号量,将信号量值加1,释放资源。
int sem_post(sem_t *sem);//V操作
2.基于环形队列的生产消费模型
环形队列采用数组模拟,用模运算来模拟环状特性;当下标++至数组尾部时,将其置为0。
#pragma once
#include<iostream>
#include<semaphore.h>
#include<sys/sem.h>
#include<vector>
#include<unistd.h>
using namespace std;
#define NUM 10//宏定义全局变量NUM,作为环形队列容量大小
class ringQueue
private:
vector<int> v;//vector一个数组模拟环形队列
int max_cap;//环形队列的容量
sem_t sem_blank;//队列中空格;生产者所关注
sem_t sem_data;//队列中数据;消费者所关注
int con_i;//生产者索引
int pro_i;//消费者索引
public:
//P操作,等待信号量,会将信号量的值减1,请求资源
void P(sem_t &s)
sem_wait(&s);
//V操作,发布信号量,将信号量值加1,释放资源
void V(sem_t &s)
sem_post(&s);
public:
ringQueue(int _cap=NUM):max_cap(_cap),v(_cap)
//刚开始时,blank(空格子)数量为NUM,data(数据)数量为0;两者下标均为0;
sem_init(&sem_blank,0,NUM);
sem_init(&sem_data,0,0);
con_i=0;pro_i=0;
~ringQueue()
sem_destroy(&sem_blank);
sem_destroy(&sem_data);
con_i=pro_i=0;
//消费者消费;取出值
void Get(int &out)
//请求data资源并取出
P(sem_data);
out=v[con_i];
con_i++;
//取完数据后将消费者下标con_i归零
con_i%=max_cap;
//释放blank资源
V(sem_blank);
//生产者生产:放入值
void Put(const int &in)
//请求blank资源并放入数据
P(sem_blank);
v[pro_i]=in;
pro_i++;
//放满数据后将消费者下标con_i归零
pro_i%=max_cap;
//释放data资源
V(sem_data);
;
(1)生产快&&消费慢
#include "ringQueue.h"
using namespace std;
//在环形队列中取出数据,每取出一个数据之后打印"consumer done!"。
void *consumer(void *ring_queue)
ringQueue *rq=(ringQueue*)ring_queue;
while(true)
sleep(1);
int data=1;
rq->Get(data);
cout<<"consumer done# "<<data<<endl;
//向环形队列中放入数据,每放入一次数据之后打印"productor done!"。
void *productor(void *ring_queue)
ringQueue *rq=(ringQueue*)ring_queue;
int count=0;
while(true)
//sleep(1);
rq->Put(count);
count++;
if(count==9)
count=0;
cout<<"productor done!"<<endl;
int main()
pthread_t con,pro;
ringQueue *rq=new ringQueue();
pthread_create(&con,nullptr,consumer,rq);
pthread_create(&pro,nullptr,productor,rq);
pthread_join(con,nullptr);
pthread_join(pro,nullptr);
return 0;
运行截图
(1)生产慢&&消费快
只是让消费者取出数据之后不在sleep(1);而是让生产者放入数据之后sleep(1)。
#include "ringQueue.h"
using namespace std;
//在环形队列中取出数据,每取出一个数据之后打印"consumer done!"。
void *consumer(void *ring_queue)
ringQueue *rq=(ringQueue*)ring_queue;
while(true)
//sleep(1);
int data=1;
rq->Get(data);
cout<<"consumer done# "<<data<<endl;
//向环形队列中放入数据,每放入一次数据之后打印"productor done!"。
void *productor(void *ring_queue)
ringQueue *rq=(ringQueue*)ring_queue;
int count=0;
while(true)
sleep(1);
rq->Put(count);
count++;
if(count==9)
count=0;
cout<<"productor done!"<<endl;
int main()
pthread_t con,pro;
ringQueue *rq=new ringQueue();
pthread_create(&con,nullptr,consumer,rq);
pthread_create(&pro,nullptr,productor,rq);
pthread_join(con,nullptr);
pthread_join(pro,nullptr);
return 0;
线程池
1.什么是线程池
一种线程使用模式。线程过多会带来调度开销,进而影响缓存局部性和整体性能。而线程池维护着多个线程,等待着监督管理者分配可并发执行的任务。这避免了在处理短时间任务时创建与销毁线程的代价。线程池不仅能够保证内核的充分利用,还能防止过分调度。可用线程数量应该取决于可用的并发处理器、处理器内核、内存、网络sockets等的数量。
2.使用场景
- 需要大量的线程来完成任务,且完成任务的时间比较短。如:WEB服务器完成网页请求这样的任务。因为单个任务小,而任务数量巨大。 但对于长时间的任务,比如一个Telnet连接请求,线程池的优点就不明显了。因为Telnet会话时间比线程的创建时间大多了。
- 对性能要求苛刻的应用,比如要求服务器迅速响应客户请求。
- 接受突发性的大量请求,但不至于使服务器因此产生大量线程的应用。突发性大量客户请求,在没有线程池情况下,将产生大量线程,虽然理论上大部分操作系统线程数目最大值不是问题,短时间内产生大量线程可能使内存到达极限,出现错误。
3.线程池简单代码实现
#pragma once
#include<iostream>
#include<queue>
#include<unistd.h>
#include<pthread.h>
#include<math.h>
using namespace std;
#define NUM 5
//创建线程将要实现任务,这里为计算一个数的平方;一个任务便是一个线程池中的线程
class Task
public:
int num;
public:
Task()
Task(int n):num(n)
void Run()
cout<<"thread id ["<<pthread_self()<<"]"<<"task run ! num "<<num<<" pow is "<<pow(num,2)<<endl;
~Task()
;
//线程池
class threadPool
private:
queue<Task*> q;
int max_num;
pthread_mutex_t lock;
pthread_cond_t cond;//指让消费者操作
//static bool quit;
public:
//加锁
void LockQueue()
pthread_mutex_lock(&lock);
//解锁
void UnlockQueue()
pthread_mutex_unlock(&lock);
bool IsEmpty()
return q.size()==0;
//线程等待
void ThreadWait()
pthread_cond_wait(&cond,&lock);
//唤醒线程
void ThreadWakeUp()
pthread_cond_signal(&cond);
public:
threadPool(int _max=NUM):max_num(_max)
//实现单个线程的运行
static void *Rontine(void *arg)
threadPool *this_p=(threadPool*)arg;
while(true)
this_p->LockQueue();
while(this_p->IsEmpty())
this_p->ThreadWait();
Task t;
this_p->Get(t);
this_p->UnlockQueue();
t.Run();
//线程池初始化
void ThreadPoolInit()
//初始化锁与等待条件
pthread_mutex_init(&lock,nullptr);
pthread_cond_init(&cond,nullptr);
pthread_t t;
//线程池队列未满便一直放入Task任务并运行
for(int i=0;i<max_num;i++)
pthread_create(&t,nullptr,Rontine,this);
//在线程池队列中放入任务
void Put(Task &in)
LockQueue();
q.push(&in);
UnlockQueue();
ThreadWakeUp();
//取出并执行任务
void Get(Task &out)
Task*t=q.front();
q.pop();
out=*t;
~threadPool()
pthread_mutex_destroy(&lock);
pthread_cond_destroy(&cond);
;
#include "threadPool.h"
using namespace std;
int main()
threadPool *tp = new threadPool();
tp->ThreadPoolInit();
while(true)
sleep(1);
int x=rand()%10+1;
Task t(x);
tp->Put(t);
return 0;
运行截图:下图中可见很多不同的线程在一起运行,thread id是不同的
以上是关于linux:线程 POSIX信号量&&线程池的主要内容,如果未能解决你的问题,请参考以下文章
POSIX(Linux多线程)使用信号量三个线程顺序打印十次123
Linux篇第十五篇——多线程(生产消费模型+POSIX信号量)