c++多线程模拟银行排队

每一个窗口对应一个线程,还是存在一些关于并发的问题,用户都是随机数生成,无法模拟实际情况,互斥锁锁住之后,存在只有一个线程掌握资源的情况。试图解决方案,把互斥锁,条件变量全部封装到一个类,模拟单生产者,多消费者模型。

或者修改成几个窗口,几个队列

main.cpp

//
//  main.cpp
//  模拟银行排队
//
//  Created by 蓝猫 on 2019/3/15.
//  Copyright © 2019年 蓝猫. All rights reserved.
//
/*
 业务逻辑:
 首先我们要分析银行提供服务的逻辑。在银行服务中,所有顾客都是通过取号排队的方式等待服务的,这和火车站买票有所不同,在火车站买票时,顾客必须在某一个窗口所排的队列下进行排队,且无法变更自己所属的窗口,否则只能从队尾重新排队。换句话说,对于银行提供的服务来说,所有用户都是位于同一个队列上的,当某个服务窗口可用时,才会从排队队列的队首取出一个新的用户来办理银行业务。即代码实现过程中,服务窗口可以创建 w 个,但只需要实现一个顾客队列即可。
 
 其次,对于顾客而言,有两个属性是能够被抽象出来的:
 
 到达银行的时间;
 需要服务的时间。
 
 感觉类似线程池,每一个顾客是任务,
 */
#include <iostream>
#include <string>
#include "Bank.hpp"
static std::string  getCurrentTimeStr()
{
    time_t t = time(NULL);
    char ch[64] = {0};
    strftime(ch, sizeof(ch) - 1, "%Y-%m-%d %H:%M:%S", localtime(&t));     //年-月-日 时-分-秒
    return ch;
}

int main(int argc, const char * argv[])
{
    const int win_num=3;
    //std::cout <<   getCurrentTimeStr()<<"\n";
    int time1,time2;
    std::cout<<"======================欢迎光临蓝猫银行======================"<<std::endl;
    std::cout <<"请输入银行开门和关门时间,9:00-12:00,请输入9 12"<<"\n";
    std::cout<<"窗口数量:"<<win_num<<std::endl;
    cin>>time1>>time2;
    Bank b(time1,time2,win_num);
    //b.Main();
    b. Main_thread();
    return 0;
}

Bank.cpp&&hpp

//
//  Bank.hpp
//  模拟银行排队
//
//  Created by 蓝猫 on 2019/3/18.
//  Copyright © 2019年 蓝猫. All rights reserved.
//

#ifndef Bank_hpp
#define Bank_hpp

#include <stdio.h>
#include <iostream>
#include <queue>
#include <cstdlib>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <chrono>
#include "Customer.hpp"
#include "Win.hpp"

class Bank
{
private:
    bool exit;//是否销毁所有线程
    std::mutex mutex_t;
    std::condition_variable cond;//队列空的条件变量
    //std::condition_variable conds;//每个窗口繁忙的条件变量
    std::vector<std::thread> wins_thread;//线程窗口 每个线程对应下标相同的窗口
    
    
    int open_time;//开门时间 输入多少 就是几点
    int close_time;//关门时间 输入多少 就是几点
    int close_time2;//关门时间 开门后分钟
    int last;//  转换成开门后的分钟 最后被允许取号的时间
    int arr_time;//( 上一个顾客来的时间) 通过它来随机产生顾客顺序到来
    int num_customer;//顾客数量
    int num_win;//窗口数量
    std::vector<Win> win_v;//窗口数量
    std::queue<Customer> que;//顾客队列
public:
    Bank(int t1,int t2,int num):open_time(t1),close_time(t2),num_win(num)
    {
        close_time2=(close_time-open_time)*60;
        last=(close_time-open_time)*60-20;//提前二十分钟不能取号
        arr_time=0;
        num_customer=0;
        for(int i=0;i<num_win;i++)
        {
            Win w;
            w.set_num(i);
            win_v.emplace_back(w);
        }
    };
    ~Bank() { Del_thread(); };
    void Create_Customer_thread();//多线程版本 产生用户放入队列 需要一个生产者线程
    void Create_thread();//创造线程
    void Del_thread(); //中止线程
    void Customer_into_thread(int i);//顾客处理函数 i窗口下标
    void Win_Customer_thread(int pos,Customer c);
    void Main_thread();
    
    void Main();
    void Create_Customer();//产生用户放入队列
    void Customer_into();//顾客处理函数
    void Win_Customer(int pos,Customer);//顾客办理业务
    void print_time(int time);//打印时间为时分秒那种
    void print_cust(Customer c);//顾客离开 打印顾客信息
    
};
#endif /* Bank_hpp */
//
//  Bank.cpp
//  模拟银行排队
//
//  Created by 蓝猫 on 2019/3/18.
//  Copyright © 2019年 蓝猫. All rights reserved.
//

#include "Bank.hpp"
using namespace std;
void Bank::Create_Customer_thread()//;//多线程版本 产生用户放入队列 需要一个生产者线程
{
    while (1)
    {
        int arrive = rand() % 8 + 1 + arr_time;//随机产生一个用户进入队列 1-8内来一个
        std::this_thread::sleep_for(std::chrono::milliseconds(arrive- arr_time+500));
        //std::this_thread::sleep_for(std::chrono::seconds(arrive- arr_time));
        if (arrive > close_time2)
        {
            print_time(arrive);
            cout << "已经关门了 明个再来" << endl;
            exit = true;
            break;
        }
        
        arr_time = arrive;
        //bool empty = que.empty();//判断之前是否为空
        std::unique_lock<std::mutex> lk(mutex_t);//锁住
        Customer cust(num_customer, arrive);//多线程版本 办理业务时间在线程函数中生成
        que.push(cust);
        num_customer++;
        cond.notify_one();
        
    }
}
void Bank:: Create_thread()
{
    for (int i = 0; i < num_win; i++)
    {
        printf("窗口%d就绪\n",i+1);
        wins_thread.emplace_back(std::thread(&Bank::Customer_into_thread,this,i));
        std::condition_variable temp;
        //conds.push_back(temp);
    }
};
void Bank:: Del_thread() //中止线程
{
    for (int i = 0; i < wins_thread.size(); i++)
    {
        wins_thread[i].join();
        
    }
}
void Bank:: Customer_into_thread(int i)//;//顾客处理函数 i窗口下标
{
    while (1)
    {
        std::unique_lock<std::mutex> lk(mutex_t);//互斥锁 锁住
        //事实上用于不会很忙
        while (que.empty()||win_v[i].is_busy())//如果队列空或者窗口很忙 等待
        {
            //if(win_v[i].is_busy())printf("窗口%d繁忙\n",i+1);
            //if(que.empty())printf("队列空 窗口%d空闲\n",i+1);
            cond.wait(lk);
        }
       
        if (que.empty() && exit)
        {
            cond.notify_all();
            break;//银行下班了
        }
        //不忙且队列不空
        Customer c = que.front();
        que.pop();
        //lk.unlock();
        if (c.get_arrive_time() > last)
        {
            cout << c.get_id() << "号 到达:";
            print_time(c.get_arrive_time());
            cout << "准备关门了 明个再来" << endl;
            cond.notify_all();
        }
        else
        {
            int process = rand() % 20 + 1 + 5;//业务办理时间  5-25min
            c.set_process_time(process);
            Win_Customer_thread(i, c);
        }
        
    }
    //Del_thread();
}

void Bank::Win_Customer_thread(int pos,Customer c)//顾客办理业务  这个w必须传实参 因为窗口会变的
{
    win_v[pos].set_busy();
    c.set_wait_time(win_v[pos].get_last_time());
    cout<<"窗口:"<<win_v[pos].get_num()+1<<" ";
    print_cust(c);
    win_v[pos].set_last_time(c.get_leave_time());//窗口更新时间
    cout<<endl;
    std::this_thread::sleep_for(std::chrono::milliseconds(c.get_process_time()));
    //std::this_thread::sleep_for(std::chrono::seconds(c.get_process_time()));
    //多线程版本用这个 表示正在办理业务
    win_v[pos].set_nobusy();
}


void Bank:: Main_thread()//;
{
    Create_thread();
    Create_Customer_thread();
    //Create_thread();
    
}

void Bank::Main()
{
    
    Create_Customer();
    Customer_into();
}

void Bank::print_time(int time)//time是分钟
{
    int hour=time/60+open_time;
    int min=time%60;
    cout<<hour<<":"<<min<<" ";
};
void Bank::Create_Customer()//产生用户放入队列
{
    while (1)
    {
        int arrive=rand()%10+1+arr_time;//随机产生一个用户进入队列 1-30内来一个
        if(arrive>close_time2)
        {
            print_time(arrive);
            cout<<"已经关门了 明个再来"<<endl;
            break;
        }
        /*
        if(arrive>last)
        {
            cout<<"准备关门了 明个再来"<<endl;
            break;
        }
         */
        int process=rand()%20+1+5;//业务办理时间  5-25min
        arr_time=arrive;
        Customer cust(num_customer,arrive,process);
        que.push(cust);
        num_customer++;

    }
}
void Bank::Customer_into()//顾客处理函数
{
    /*
    for(auto x:win_v)
    {
        cout<<x.get_num()<<" "<<x.get_last_time()<<endl;
    }*/
    while (!que.empty())
    {
        Customer c=que.front();
        que.pop();
        if(c.get_arrive_time()>last)
        {
            cout<<c.get_id()<<"号 到达:";
            print_time(c.get_arrive_time());
            cout<<"准备关门了 明个再来"<<endl;
        }
        else
        {
            //Win w=win_v[0];
            int pos=0;// pos和窗口编号不一样!!!!
            int min_wait=INT_MAX;
            
            for(auto x:win_v)
            {
                //cout<<x.get_num()<<" "<<x.get_last_time()<<endl;
                if(x.get_last_time()<c.get_arrive_time())//不用等
                {
                    //cout<<"no wait"<<x.get_last_time()<<" "<<c.get_arrive_time()<<endl;
                    pos=x.get_num();
                    break;//记住加break
                    //cout<<w.get_num()<<endl;
                }
                else//那个窗口等的时间最短
                {
                    if(min_wait>(x.get_last_time()-c.get_arrive_time()))
                    {
                        //cout<<"wait"<<endl;
                        pos=x.get_num();
                        min_wait=x.get_last_time()-c.get_arrive_time();
                    }
                }
            }
            Win_Customer(pos,c);
            cout<<endl;
        }
    }
}
void Bank::Win_Customer(int pos,Customer c)//顾客办理业务  这个w必须传实参 因为窗口会变的
{
    win_v[pos].set_busy();
    c.set_wait_time(win_v[pos].get_last_time());
    cout<<"窗口:"<<win_v[pos].get_num()+1<<" ";
    print_cust(c);
    win_v[pos].set_last_time(c.get_leave_time());//窗口更新时间
    cout<<endl;
    /*
    for(int i=0;i<win_v.size();i++)
    {
        cout<<win_v[i].get_num()<<" "<<win_v[i].get_last_time()<<endl;
    }
     */
    std::this_thread::sleep_for(std::chrono::milliseconds(c.get_process_time()));
    //std::this_thread::sleep_for(std::chrono::seconds(c.get_process_time()));
    //多线程版本用这个 表示正在办理业务
    win_v[pos].set_nobusy();
    
}

void Bank:: print_cust(Customer c)
{
    cout<<c.get_id()<<"号 到达:";
    print_time(c.get_arrive_time());
    cout<<" 离开:";
    print_time(c.get_leave_time());
    cout<<" 等待:"<<c.get_wait_time();
    
    //print_time(c.get_wait_time());
    cout<<" 开始办理:";
    print_time(c.get_start_time());
    cout<<" 业务时间:"<<c.get_process_time();
    //print_time(c.get_process_time());
    cout<<" 总时间:"<<c.get_total_time();
    //print_time(c.get_total_time());
}

Customer.hpp&&cpp cpp空

//
//  Customer.hpp
//  模拟银行排队
//
//  Created by 蓝猫 on 2019/3/15.
//  Copyright © 2019年 蓝猫. All rights reserved.
//

#ifndef Customer_hpp
#define Customer_hpp

#include <stdio.h>
#include <iostream>
#include<cstdlib>
using namespace std;
class Customer
{
private:
    //时间全部为开门之后的多少分钟
    int id;//顾客id
    //int win;//在那个窗口办理
    int arrive_time;//到达时间
    int leave_time;//离开时间
    int wait_time;//等待时间
    int start_time;//开始办理业务时间
    int process_time;//办理业务过程时间
    int total_time;//在银行呆的时间
public:
    Customer(int num,int time1,int time2):id(num),arrive_time(time1),process_time(time2)
    {
        
    };
    Customer(int num, int time1) :id(num), arrive_time(time1)//多线程版本 业务时间不着急产生
    {
        
    };
    
    inline int get_id()
    {
        return id;
    }

    //到达时间
    inline void set_arrive_time(int time)
    {
        arrive_time=time;
    }
    inline int get_arrive_time()
    {
        return arrive_time;
    }
    //离开时间
    inline int get_leave_time()
    {
        leave_time=start_time+process_time;
        return leave_time;
    }
    //业务开始时间
    inline int get_start_time()
    {
        return start_time;
    }
    //等待时机
    inline void set_wait_time(int time)//参数是窗口上一个用户结束时间
    {
        if(arrive_time>=time)//不用等待
        {
            wait_time=0;
        }
        else
        {
            wait_time=time-arrive_time;
        }
        start_time=arrive_time+wait_time;
    }
    inline int get_wait_time()
    {
        return wait_time;
    }
    //业务时机
    inline void set_process_time(int time)
    {
       process_time=time;
    }

    inline int get_process_time()
    {
        return process_time;
    }
    //总时间
    inline int get_total_time()
    {
        return leave_time-arrive_time;
    }

 };
#endif /* Customer_hpp */

 

Win.hpp&&cpp cpp为空

//
//  Win.hpp
//  模拟银行排队
//
//  Created by 蓝猫 on 2019/3/18.
//  Copyright © 2019年 蓝猫. All rights reserved.
//

#ifndef Win_hpp
#define Win_hpp

#include <stdio.h>
class Win
{
private:
    int num;//窗口号码
    bool isbusy;
    int last_time;//上一个刚结束的时间 
public:
    Win()
    {
        isbusy=false;
        last_time=0;
    };
    void set_num(int n)
    {
        num=n;
    }

    void set_busy()
    {
        isbusy=true;
    }
    void set_nobusy()
    {
        isbusy=false;
    }
    void set_last_time(int time)
    {
        last_time=time;
    }
    inline int get_last_time()
    {
        return last_time;
    }
    inline int get_num()
    {
        return num;
    }
    inline bool is_busy()
    {
        return isbusy;
    }
};
#endif /* Win_hpp */

结果

======================欢迎光临蓝猫银行======================
请输入银行开门和关门时间,9:00-12:00,请输入9 12
窗口数量:3
9 12
窗口1就绪
窗口2就绪
窗口3就绪
窗口:2 0号 到达:9:8  离开:9:27  等待:0 开始办理:9:8  业务时间:19 总时间:19
窗口:1 1号 到达:9:10  离开:9:26  等待:0 开始办理:9:10  业务时间:16 总时间:16
窗口:3 2号 到达:9:13  离开:9:23  等待:0 开始办理:9:13  业务时间:10 总时间:10
窗口:2 3号 到达:9:14  离开:9:36  等待:13 开始办理:9:27  业务时间:9 总时间:22
窗口:1 4号 到达:9:21  离开:9:32  等待:5 开始办理:9:26  业务时间:6 总时间:11
窗口:3 5号 到达:9:27  离开:9:45  等待:0 开始办理:9:27  业务时间:18 总时间:18
窗口:2 6号 到达:9:33  离开:9:49  等待:3 开始办理:9:36  业务时间:13 总时间:16
窗口:1 7号 到达:9:36  离开:9:49  等待:0 开始办理:9:36  业务时间:13 总时间:13
窗口:3 8号 到达:9:44  离开:9:51  等待:1 开始办理:9:45  业务时间:6 总时间:7
窗口:2 9号 到达:9:46  离开:9:58  等待:3 开始办理:9:49  业务时间:9 总时间:12
窗口:1 10号 到达:9:51  离开:10:6  等待:0 开始办理:9:51  业务时间:15 总时间:15
窗口:3 11号 到达:9:53  离开:9:59  等待:0 开始办理:9:53  业务时间:6 总时间:6
窗口:2 12号 到达:9:59  离开:10:24  等待:0 开始办理:9:59  业务时间:25 总时间:25
窗口:1 13号 到达:10:5  离开:10:28  等待:1 开始办理:10:6  业务时间:22 总时间:23
窗口:3 14号 到达:10:12  离开:10:35  等待:0 开始办理:10:12  业务时间:23 总时间:23
窗口:2 15号 到达:10:20  离开:10:42  等待:4 开始办理:10:24  业务时间:18 总时间:22
窗口:1 16号 到达:10:23  离开:10:44  等待:5 开始办理:10:28  业务时间:16 总时间:21
窗口:3 17号 到达:10:27  离开:11:0  等待:8 开始办理:10:35  业务时间:25 总时间:33
窗口:2 18号 到达:10:29  离开:11:7  等待:13 开始办理:10:42  业务时间:25 总时间:38
窗口:1 19号 到达:10:35  离开:10:57  等待:9 开始办理:10:44  业务时间:13 总时间:22
窗口:3 20号 到达:10:41  离开:11:19  等待:19 开始办理:11:0  业务时间:19 总时间:38
窗口:2 21号 到达:10:42  离开:11:18  等待:25 开始办理:11:7  业务时间:11 总时间:36
窗口:1 22号 到达:10:43  离开:11:11  等待:14 开始办理:10:57  业务时间:14 总时间:28
窗口:3 23号 到达:10:45  离开:11:39  等待:34 开始办理:11:19  业务时间:20 总时间:54
窗口:2 24号 到达:10:49  离开:11:25  等待:29 开始办理:11:18  业务时间:7 总时间:36
窗口:1 25号 到达:10:55  离开:11:25  等待:16 开始办理:11:11  业务时间:14 总时间:30
窗口:3 26号 到达:10:57  离开:11:53  等待:42 开始办理:11:39  业务时间:14 总时间:56
窗口:2 27号 到达:10:58  离开:11:35  等待:27 开始办理:11:25  业务时间:10 总时间:37
窗口:1 28号 到达:11:1  离开:11:41  等待:24 开始办理:11:25  业务时间:16 总时间:40
窗口:3 29号 到达:11:6  离开:12:1  等待:47 开始办理:11:53  业务时间:8 总时间:55
窗口:2 30号 到达:11:14  离开:11:50  等待:21 开始办理:11:35  业务时间:15 总时间:36
窗口:1 31号 到达:11:17  离开:11:48  等待:24 开始办理:11:41  业务时间:7 总时间:31
窗口:3 32号 到达:11:18  离开:12:24  等待:43 开始办理:12:1  业务时间:23 总时间:66
窗口:2 33号 到达:11:24  离开:12:4  等待:26 开始办理:11:50  业务时间:14 总时间:40
窗口:1 34号 到达:11:25  离开:12:12  等待:23 开始办理:11:48  业务时间:24 总时间:47
窗口:3 35号 到达:11:31  离开:12:45  等待:53 开始办理:12:24  业务时间:21 总时间:74
窗口:2 36号 到达:11:37  离开:12:15  等待:27 开始办理:12:4  业务时间:11 总时间:38
37号 到达:11:43 准备关门了 明个再来
38号 到达:11:50 准备关门了 明个再来
39号 到达:11:58 准备关门了 明个再来
40号 到达:11:59 准备关门了 明个再来
12:1 已经关门了 明个再来

 

  • 0
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值