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.使用场景

  1. 需要大量的线程来完成任务,且完成任务的时间比较短。如:WEB服务器完成网页请求这样的任务。因为单个任务小,而任务数量巨大。 但对于长时间的任务,比如一个Telnet连接请求,线程池的优点就不明显了。因为Telnet会话时间比线程的创建时间大多了。
  2. 对性能要求苛刻的应用,比如要求服务器迅速响应客户请求。
  3. 接受突发性的大量请求,但不至于使服务器因此产生大量线程的应用。突发性大量客户请求,在没有线程池情况下,将产生大量线程,虽然理论上大部分操作系统线程数目最大值不是问题,短时间内产生大量线程可能使内存到达极限,出现错误。

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信号量&&线程池的主要内容,如果未能解决你的问题,请参考以下文章

Linux 多线程编程(二)2019-08-10

POSIX(Linux多线程)使用信号量三个线程顺序打印十次123

Linux信号量

Linux篇第十五篇——多线程(生产消费模型+POSIX信号量)

Linux篇第十五篇——多线程(生产消费模型+POSIX信号量)

linux进程间通信之Posix 信号量用法详解代码举例