c++回调函数、同步队列、生产者消费者举例

C++11 同步队列、注册回调函数、生产者消费者代码记录

同步队列:
// data queue
template <typename T>
class SynchronizedQueue {
public:
    SynchronizedQueue()
        : queue_()
        , mutex_()
        , cond_()
        , request_to_end_(false)
        , enqueue_data_(true)
    {
    }

    void enqueue(const T& data)
    {
        std::unique_lock<std::mutex> lock(mutex_);

        if (enqueue_data_)
        {
            queue_.push(data);
            cond_.notify_one();
        }
    }

    bool dequeue(T& result)
    {
        std::unique_lock<std::mutex> lock(mutex_);

        while (queue_.empty() && (!request_to_end_))
        {
            cond_.wait(lock);
        }

        if (request_to_end_)
        {
            doEndActions();
            return false;
        }

        result = queue_.front();
        queue_.pop();

        return true;
    }

    void stopQueue()
    {
        std::unique_lock<std::mutex> lock(mutex_);
        request_to_end_ = true;
        cond_.notify_one();
    }

    unsigned int size()
    {
        std::unique_lock<std::mutex> lock(mutex_);
        return static_cast<unsigned int>(queue_.size());
    }

    bool isEmpty() const
    {
        std::unique_lock<std::mutex> lock(mutex_);
        return (queue_.empty());
    }

private:
    void doEndActions()
    {
        enqueue_data_ = false;

        while (!queue_.empty())
        {
            queue_.pop();
        }
    }

    std::queue<T> queue_;            // Use STL queue to store data
    mutable std::mutex mutex_;     // The mutex to synchronise on
    std::condition_variable cond_; // The condition to wait for

    bool request_to_end_;
    bool enqueue_data_;
};
Task基类:
// task base
class BaseTask {
public:

    using PrintFunc = std::function<void(int level, std::string& msg)>;

    BaseTask() = default;
    virtual ~BaseTask() = default;
    virtual void Start() {}
    virtual void Stop() {}

    virtual void RegisterPrint(PrintFunc cb) {
        print_ = cb;
    }
protected:

    volatile bool stop_flag_ = false;

    std::shared_ptr<std::thread> worker_ = nullptr;
    virtual void Process(std::string name) {}
    virtual void Print(int level, std::string msg) {
        if (this->print_)
            this->print_(0, msg);
    }

    PrintFunc print_ = nullptr;

};
Task派生类,生产者
// producer
template <typename T>
class Producer :public BaseTask {
public:

    using DataCallBack = std::function<void(T&)>;

    Producer() {}
    virtual ~Producer() override { this->Stop(); }
    Producer(const Producer & r) = default;
    Producer &operator=(const Producer &r) = default;

    virtual void Start() override {
        if (worker_)
            return;
        else {
            worker_.reset(new std::thread(std::bind(&Producer::Process, this, std::string("Producer thread"))));
        }
    }

    virtual void Stop() override {
        if (!worker_)
            return;

        stop_flag_ = true;
        worker_->join();
        worker_.reset();
        stop_flag_ = false;
    }

    void RegisterDataCallback(DataCallBack cb) { cb_ = cb; }

protected:
    virtual void Process(std::string name) override {

        int i = 0;
        while (!stop_flag_) {
            // sleep
            std::this_thread::sleep_for(std::chrono::milliseconds(1000));

            // product
            T data = i++;
            if (cb_) cb_(data);
            
            // time string
            const int buffer_len = 128;
            time_t t = time(0);
            struct tm* now = localtime(&t);
            char buffer[buffer_len];
            strftime(buffer, buffer_len, "%Y-%m-%d_%H_%M_%S", now);
            Print(0, name + std::string(", ") + std::string(buffer) + std::string(": ") + std::to_string(data));
        }
    }

private:

    DataCallBack cb_ = nullptr;

};
Task派生类,消费者
// consumer
template <typename T>
class Consumer:public BaseTask {
public:

    Consumer(): datas_(new SynchronizedQueue<T>), producer_(new Producer<T>){}
    virtual ~Consumer() override { this->Stop(); }
    Consumer(const Consumer & r) = default;
    Consumer &operator=(const Consumer &r) = default;

    virtual void Start() override {
        if (worker_)
            return;
        else {
            producer_->RegisterDataCallback(std::bind(&Consumer::DataCallback, this, std::placeholders::_1));
            producer_->Start();
            worker_.reset(new std::thread(std::bind(&Consumer::Process, this, std::string("Worker thread"))));
        }
    }

    virtual void Stop() override {
        if (!worker_)
            return;

        producer_->Stop();

        stop_flag_ = true;
        worker_->join();
        worker_.reset();
        stop_flag_ = false;
    }

    virtual void RegisterPrint(PrintFunc cb) override {
        print_ = cb;
        this->producer_->RegisterPrint(cb);
    }

protected:
    virtual void Process(std::string name) override {
        while (!stop_flag_) {
            // sleep
            std::this_thread::sleep_for(std::chrono::milliseconds(1000));

            //consume
            T data;
            this->datas_->dequeue(data);

            // time string
            const int buffer_len = 128;
            time_t t = time(0);
            struct tm* now = localtime(&t);
            char buffer[buffer_len];
            strftime(buffer, buffer_len, "%Y-%m-%d_%H_%M_%S", now);
            Print(0, name + std::string(", ") + std::string(buffer) + std::string(": ") + std::to_string(data));
        }
    }

    void DataCallback(T& data) {
        if (datas_)
            datas_->enqueue(data);
    }


private:

    std::shared_ptr<SynchronizedQueue<T>> datas_ = nullptr;
    std::shared_ptr<Producer<T> > producer_ = nullptr;
    volatile bool stop_flag_ = false;

};

测试函数
//test
int main(int argc, char** argv)
{
    Notify notify;
    Consumer<int> consumer_;
    consumer_.RegisterPrint(std::bind(&Notify::Print, &notify, std::placeholders::_1, std::placeholders::_2));
    consumer_.Start();
    while (1) {
        std::this_thread::sleep_for(std::chrono::milliseconds(1000));
    }
    return 0;
}
全部代码
#include <memory>
#include <iostream>
#include <thread>
#include <queue>
#include <string>
#include <mutex>
#include <functional>
#include <condition_variable>


// used for print function
class Notify {
public:
    Notify() {}
    ~Notify() {}
    Notify(const Notify & r) = default;
    Notify &operator=(const Notify &rhs) = default;

    void Print(int level, std::string& msg) {
        switch (level) {
        case 0:
            std::cout << msg << std::endl;
            break;
        case 1:
        default:
            std::cerr << msg << std::endl;
        }
    }
};

// data queue
template <typename T>
class SynchronizedQueue {
public:
    SynchronizedQueue()
        : queue_()
        , mutex_()
        , cond_()
        , request_to_end_(false)
        , enqueue_data_(true)
    {
    }

    void enqueue(const T& data)
    {
        std::unique_lock<std::mutex> lock(mutex_);

        if (enqueue_data_)
        {
            queue_.push(data);
            cond_.notify_one();
        }
    }

    bool dequeue(T& result)
    {
        std::unique_lock<std::mutex> lock(mutex_);

        while (queue_.empty() && (!request_to_end_))
        {
            cond_.wait(lock);
        }

        if (request_to_end_)
        {
            doEndActions();
            return false;
        }

        result = queue_.front();
        queue_.pop();

        return true;
    }

    void stopQueue()
    {
        std::unique_lock<std::mutex> lock(mutex_);
        request_to_end_ = true;
        cond_.notify_one();
    }

    unsigned int size()
    {
        std::unique_lock<std::mutex> lock(mutex_);
        return static_cast<unsigned int>(queue_.size());
    }

    bool isEmpty() const
    {
        std::unique_lock<std::mutex> lock(mutex_);
        return (queue_.empty());
    }

private:
    void doEndActions()
    {
        enqueue_data_ = false;

        while (!queue_.empty())
        {
            queue_.pop();
        }
    }

    std::queue<T> queue_;            // Use STL queue to store data
    mutable std::mutex mutex_;     // The mutex to synchronise on
    std::condition_variable cond_; // The condition to wait for

    bool request_to_end_;
    bool enqueue_data_;
};

// task base
class BaseTask {
public:

    using PrintFunc = std::function<void(int level, std::string& msg)>;

    BaseTask() = default;
    virtual ~BaseTask() = default;
    virtual void Start() {}
    virtual void Stop() {}

    virtual void RegisterPrint(PrintFunc cb) {
        print_ = cb;
    }
protected:

    volatile bool stop_flag_ = false;

    std::shared_ptr<std::thread> worker_ = nullptr;
    virtual void Process(std::string name) {}
    virtual void Print(int level, std::string msg) {
        if (this->print_)
            this->print_(0, msg);
    }

    PrintFunc print_ = nullptr;

};

// producer
template <typename T>
class Producer :public BaseTask {
public:

    using DataCallBack = std::function<void(T&)>;

    Producer() {}
    virtual ~Producer() override { this->Stop(); }
    Producer(const Producer & r) = default;
    Producer &operator=(const Producer &r) = default;

    virtual void Start() override {
        if (worker_)
            return;
        else {
            worker_.reset(new std::thread(std::bind(&Producer::Process, this, std::string("Producer thread"))));
        }
    }

    virtual void Stop() override {
        if (!worker_)
            return;

        stop_flag_ = true;
        worker_->join();
        worker_.reset();
        stop_flag_ = false;
    }

    void RegisterDataCallback(DataCallBack cb) { cb_ = cb; }

protected:
    virtual void Process(std::string name) override {

        int i = 0;
        while (!stop_flag_) {
            // sleep
            std::this_thread::sleep_for(std::chrono::milliseconds(1000));

            // product
            T data = i++;
            if (cb_) cb_(data);
            
            // time string
            const int buffer_len = 128;
            time_t t = time(0);
            struct tm* now = localtime(&t);
            char buffer[buffer_len];
            strftime(buffer, buffer_len, "%Y-%m-%d_%H_%M_%S", now);
            Print(0, name + std::string(", ") + std::string(buffer) + std::string(": ") + std::to_string(data));
        }
    }

private:

    DataCallBack cb_ = nullptr;

};

// consumer
template <typename T>
class Consumer:public BaseTask {
public:

    Consumer(): datas_(new SynchronizedQueue<T>), producer_(new Producer<T>){}
    virtual ~Consumer() override { this->Stop(); }
    Consumer(const Consumer & r) = default;
    Consumer &operator=(const Consumer &r) = default;

    virtual void Start() override {
        if (worker_)
            return;
        else {
            producer_->RegisterDataCallback(std::bind(&Consumer::DataCallback, this, std::placeholders::_1));
            producer_->Start();
            worker_.reset(new std::thread(std::bind(&Consumer::Process, this, std::string("Worker thread"))));
        }
    }

    virtual void Stop() override {
        if (!worker_)
            return;

        producer_->Stop();

        stop_flag_ = true;
        worker_->join();
        worker_.reset();
        stop_flag_ = false;
    }

    virtual void RegisterPrint(PrintFunc cb) override {
        print_ = cb;
        this->producer_->RegisterPrint(cb);
    }

protected:
    virtual void Process(std::string name) override {
        while (!stop_flag_) {
            // sleep
            std::this_thread::sleep_for(std::chrono::milliseconds(1000));

            //consume
            T data;
            this->datas_->dequeue(data);

            // time string
            const int buffer_len = 128;
            time_t t = time(0);
            struct tm* now = localtime(&t);
            char buffer[buffer_len];
            strftime(buffer, buffer_len, "%Y-%m-%d_%H_%M_%S", now);
            Print(0, name + std::string(", ") + std::string(buffer) + std::string(": ") + std::to_string(data));
        }
    }

    void DataCallback(T& data) {
        if (datas_)
            datas_->enqueue(data);
    }


private:

    std::shared_ptr<SynchronizedQueue<T>> datas_ = nullptr;
    std::shared_ptr<Producer<T> > producer_ = nullptr;
    volatile bool stop_flag_ = false;

};

//test
int main(int argc, char** argv)
{
    Notify notify;
    Consumer<int> consumer_;
    consumer_.RegisterPrint(std::bind(&Notify::Print, &notify, std::placeholders::_1, std::placeholders::_2));
    consumer_.Start();
    while (1) {
        std::this_thread::sleep_for(std::chrono::milliseconds(1000));
    }
    return 0;
}

CmakeLists文件
cmake_minimum_required(VERSION 3.0)

set(DEMO_NAME producer_consumer)
add_executable(${DEMO_NAME} producer_consumer.cpp)

set(MAJOR_VERSION "0")
set(MINOR_VERSION "0")
set(PATCH_VERSION "0")
set(VERSION_STRING "${MAJOR_VERSION}.${MINOR_VERSION}.${PATCH_VERSION}")

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11  -pthread" )

target_compile_options(${DEMO_NAME}
        PRIVATE $<$<CXX_COMPILER_ID:GNU>:-Wall -Werror -Wno-c++11-long-long>
        PRIVATE $<$<CXX_COMPILER_ID:AppleClang>:-Wno-unknown-pragmas -Wall -Werror -Wno-c++11-long-long>
        PRIVATE $<$<CXX_COMPILER_ID:Clang>:-Wno-unknown-pragmas -Wall -Werror -Wno-c++11-long-long>)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值