漫话linux:教你如何用多线程操作实现cp模型(饿汉模式)(mini项目)

随着单例模式的完成,linux的系统部分(还有网络哦)逐渐告一段落,是时候用一个小项目来总结一下线程向的学习了

首先是挑选单例模式:饿汉模式与懒汉模式,这里我选择不太麻烦的饿汉模式,也就是正常写,少用new来简化代码,要啥写啥,那么饿汉模式的问题是啥呢?代码冗余对服务器的速度要求高,不过我这几百行的代码也冗余不到哪里去,所以我就选择做一个饥饿的男人

然后是线程池,线程池就是把一个进程进一步细分成不同的任务,当然你都把系统调用的基本单位进程又往下分了,人家系统自己安排一下线程的顺序不过分吧?这一安排就引发了很多问题,你的进程就像一个停车场(进程),有很多车(线程)要往上停,一段时间后,肯定会发生这样的情况:有时候全是往出开的车,反而没有车往进开,大家挤来挤去出去的车更少了,而进来的入口被浪费了(线程饥饿),车太多了收费员忙不过来把隔壁车的车费结算到你头上了(线程混乱),你打算结清车费把付款吗亮出来结果被别人盗刷了(线程安全),所以,收费员用栅栏给停车场规划了一下(锁),修筑了了一车一杆的收费亭(临界区),使每次进出的只能有一辆车(互斥锁),还在大屏幕上显示了空余车位的数量,如果不够那么进来停车的人需要等待一会(线程等待),这样,我们的线程池运行就能处于一个比较丝滑的状态

还有就是我们要实现的cp模型,就是模拟消费者和生产者的关系:消费者与消费者的关系是互斥的(两个人不能同时扫码),生产者与生产者的关系是互斥的(一家厂房不能有两个企业),消费者和生产者在建立上是互斥的,在行为上是同步的(可以同时卖和买,但是消费者不能去人家生产者的厂子里吃),这就是我们用锁的规划

下面来正式实现项目

首先是Makefile

注意因为nullptr的存在必须用c++11,而且要使用外部库pthread(锁嘛)

然后是head1.hpp

#include<iostream>
#include<pthread.h>
#include<queue>

template <class T>
class blockqueue
{
  private:
    std::queue<T>q;
    int maxnum;
    pthread_mutex_t mutex;
    pthread_cond_t c;
    pthread_cond_t p;
  public:
    blockqueue(int a=20):maxnum(a)
  {
    pthread_mutex_init(&mutex,nullptr);
    pthread_cond_init(&c,nullptr);
    pthread_cond_init(&p,nullptr);
  }
    ~blockqueue()
    {
      pthread_mutex_destroy(&mutex);
      pthread_cond_destroy(&c);
      pthread_cond_destroy(&p);
    }
  void push( T &in)
  {
pthread_mutex_lock(&mutex);
while(q.size()==maxnum)
{
  pthread_cond_wait(&p,&mutex);
}
q.push(in);
pthread_cond_signal(&c);
pthread_mutex_unlock(&mutex);
  }
T pop()
{
  pthread_mutex_lock(&mutex);
  while(q.size()==0)
  {
    pthread_cond_wait(&c,&mutex);
  }
  T out=q.front();
  q.pop();
  pthread_cond_signal(&p);
  pthread_mutex_unlock(&mutex);
  return out;
}
};

这是我们的等待队列(有多线程和cp模型就必有它)(先入先出模拟清仓处理,这是我的一点拙见,如果要先入后出就写一个等待栈呗)

首先是队列长度和两个条件变量c与p,指生产者和消费者,构造函数和析构函数不必多说,来聊一下push和pop的逻辑,首先是push,参数是一个模板对象,首先队列有空位才能用吧,如果满了就让p等待一下,别生产了,有空就插入队列并且给c发个消息可以来消费了,pop函数也大同小异,值得注意的是要使用互斥锁

接下来是head2.hpp中的Task类,简单写了一个

#pragma once
#include <iostream>
#include <string>
 
class Task 
{
public:
  Task()
  {
    std::cout<<"生产了一个对象,静待消费者"<<std::endl;
  }
  void work()
  {
    std::cout<<"消费了一个对象,生产者快来补货"<<std::endl;
  }
};

最后是text.cc

#include <iostream>  
#include <pthread.h>  
#include <unistd.h>  
#include <ctime>  
#include <queue>  
#include <mutex>  
#include <condition_variable>
#include"head1.hpp"
#include"head2.hpp"
void *cwork(void* args)
{
  blockqueue<Task>*bq=static_cast<blockqueue<Task>*>(args);
  
    Task t=bq->pop();
    t.work();
  
}
void *pwork(void* args)
{
  blockqueue<Task>*bq=static_cast<blockqueue<Task>*>(args);
  
    Task t;
    bq->push(t);

  
}
int main()
{
  srand(time(nullptr));
  blockqueue<Task>*bq=new blockqueue<Task>();
  pthread_t c[4],p[5];
  for(int i=0;i<4;i++)
  {
pthread_create(c+i,nullptr,cwork,bq);
  }
  for(int j=0;j<5;j++)
  {
pthread_create(p+j,nullptr,pwork,bq);
  }
  for(int i=0;i<4;i++)
  {
    pthread_join(c[i],nullptr);
  }
  for(int j=0;j<5;j++)
  {
    pthread_join(p[j],nullptr);
  }
  delete bq;
}

cwork消费者函数就是调用类函数,pwork就是创建类,我特地多搞了几个类,要不然会有可怜的消费者在一直等

感兴趣的uu可以来搞一下这个小项目

优点:

        1.对cp模型有一个更全面的理解

        2.对多线程操作有一个整体的认识

        3.会用锁

        4.变量类型唬人,代码复杂,多文件操作,外行看热闹内行看热闹,可以小装一波

        5.快的几个小时搞定 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值