C++实现的线程安全的单例的生产者消费者代码

记录一次失败的面试手撕,写生产者消费者确实太少了,导致没撕出来。
现在手写一下都得写一个来小时,得多熟悉一下

#include<iostream>
#include<vector>
#include<thread>
#include<condition_variable>
#include<mutex>
#include<queue>
#include<chrono>

using namespace std;

int num=0;

struct Task{
    int n;
    Task(){
        n=num++;
    }
};

class ThreadSafeQueue{
    private:
    //重要点:构造函数私有化,拷贝构造和赋值函数delete
    ThreadSafeQueue(){}
    ThreadSafeQueue(ThreadSafeQueue& t)=delete;
    ThreadSafeQueue& operator=(const ThreadSafeQueue& t) = delete;
    //在这个单例模式中得有锁,多个线程访问时得保证不冲突
    std::mutex mutex_;
    std::condition_variable cv_;
    //一个存储任务的队列
    queue<Task> taskQueue_;
    //记录是否终止
    bool shutdownFlag_=false;

    public:
    //获取实例的单例静态函数
    static ThreadSafeQueue& get_instance(){
        static ThreadSafeQueue instance;//这个得是静态函数内的静态变量,保证全局存在
        return instance;
    }

    //什么时候使用这个获取大小的函数呢?如果是在内部使用的话,就不需要加锁,但是如果在外部的话需要加锁
    //加个锁吧,因为内部可以直接用queue的size函数,这个函数是给外部使用的
    int getQueueSize(){
        std::lock_guard<mutex> lock(mutex_);
        //std::unique_lock<mutex> lock(mutex_);
        return taskQueue_.size();
    }

    void put(Task t){
        std::lock_guard<mutex> lock(mutex_);
        if(shutdownFlag_) return ;
        taskQueue_.push(t);
        cv_.notify_one();
    }
    //这里最好是用这种来返回,因为这样的话,内部如果size==0了,也可以进行返回,返回提取失败
    bool get(Task& t){
        std::unique_lock<mutex> lock(mutex_);
        cv_.wait(lock,[this](){
            return !taskQueue_.empty()||shutdownFlag_;//如果返回true,就会继续执行,否则进入阻塞
        });

        if(shutdownFlag_&&taskQueue_.empty()) return false;//如果是空的且要关闭了,就返回false

        t=std::move(taskQueue_.front());
        taskQueue_.pop();
        return true;
    }

    void shutdown(){
        //这个地方可以不加锁吗?
        {
            std::lock_guard<mutex> lock(mutex_);
            shutdownFlag_=true;
        }
        cv_.notify_all();
    }
};

//生产者函数
void producer(int id){
    for(int i=0;i<5;++i){
        Task t;
        ThreadSafeQueue::get_instance().put(t);
        cout<<"producer_"<<id<<" produce the "<<t.n<<"\n";
        std::this_thread::sleep_for(std::chrono::microseconds(500));
    }
}

void consumer(int id){
    while(true){
        Task t;
        bool bResult=ThreadSafeQueue::get_instance().get(t);
        if(bResult==false){
            cout<<"the End!\n";
            break;
        }
        cout<<"consumer_"<<id<<" consume the "<<t.n<<"\n";
        std::this_thread::sleep_for(std::chrono::microseconds(500));
    }
}

int main(){
    vector<thread> producers;
    vector<thread> consumers;
    for(int i=0;i<5;++i){
        producers.emplace_back(thread(producer,i));
        consumers.emplace_back(thread(consumer,i));
    }
    for(int i=0;i<5;++i){
        producers[i].join();
    }
    ThreadSafeQueue::get_instance().shutdown();
    for(int i=0;i<5;++i){
        consumers[i].join();
    }
    return 0;
}
posted @ 2025-04-05 17:25  鹏_博客  阅读(25)  评论(0)    收藏  举报