生产者消费者示例

【背景介绍】

当前项目,需要设计一套架构,支持微服务的集群应用,其基础架构可以参考文章

项目中碰到的proxy实现以及相关架构演进

https://blog.csdn.net/weixin_44193239/article/details/131809668?spm=1001.2014.3001.5502

 

其实都是当前互联网界比较常见的一种C/S结构,特点是在Client端,user能够接触的都是各种不同微服务提供的proxy, user调用proxy实例接口,proxy组装rpc消息,这些不同proxy的消息,通过某一个context里面维护的连接,最终消息会抵达service端。

service端也存在出现某些场景,触发通知事件,该通知最终也会抵达client端,user作为observer,因为前期注册了消息处理的回调,最终该回调会得到调用。

上述是一个典型的observer/notifier模型。

另外,在设计时,也需要考虑到有可能短时间会接收大量不同service端发过来的通知/事件消息,如果只起一个线程来接收和处理消息,有可能该线程最终会在user注册的callback中耗时超出预期,导致时间窗口容许范围内,来不及接收更多消息,造成阻塞,形成实质上的瓶颈,则需要将接收消息和处理消息分隔开来。

上述又成为典型的生产者消费者模式的应用点。

observer/notifier模型,实现里面,最简单的一种就是根据key来注册callback

//核心结构以及变量
using SubscriberCb = std::function<void(int A, int B)>;
using Subscribers = std::map<std::string, SubscriberCb>;
Subscribers subscribers_;
std::mutex lock_;
//主要接口以及实现
void SubscriberManager::add(const std::string &key, SubscriberCb subscriberCb)
{
    std::lock_guard lk{lock_};

    subscribers_[key] = subscriberCb;
}

void SubscriberManager::callEventHandler(const std::string &module,
                                    int A, int B)
{
    std::lock_guard lk{lock_};

    auto cit = findSubscriber(module);
    if (cit != subscribers_.cend())
    {
        (cit->second)(A, B);
    }
}

bool SubscriberManager::subscriberFound(const std::string &module)
{
    std::lock_guard lk{lock_};

    return findSubscriber(module) != subscribers_.cend();
}

SubscriberManager::Subscribers::const_iterator SubscriberManager::findSubscriber(const std::string &module) const
{
    return subscribers_.find(module);
}

本文关注的是生产者消费者相关实现,直接上代码

#ifndef JTHREAD_SAMPLE_
#define JTHREAD_SAMPLE_

#include <memory>
#include <atomic>
#include <thread>
#include <queue>

struct NotificationMessage
{
    NotificationMessage(const std::string &module_) :
        module(module_)
    {
    }

    std::string module;
};
using NotificationMessagePtr = std::unique_ptr<NotificationMessage>;
using NotificationMessages = std::queue<NotificationMessagePtr>;


class JthreadSample
{
public:
    explicit JthreadSample();

    ~JthreadSample() override;

    JthreadSample(const JthreadSample&) = delete;
    JthreadSample(JthreadSample&&) = delete;
    JthreadSample& operator=(const JthreadSample&) = delete;
    JthreadSample& operator=(JthreadSample&&) = delete;

    void dispatch() override;


protected:
    virtual bool loopCondition(std::stop_token& stop_token);
    virtual void notificationHandler(std::stop_token stop_token);
private:

    NotificationMessages notification_messages_;

    void threadForNotificationHandler();
    void threadForEventHandler();
    void handleNotificationMessage();
    NotificationMessagePtr readOneNotificationMessage();
    void notificationHandler(std::stop_token stop_token);
    void receiveNotifications(std::stop_token &stop_token);
    static NotificationMessagePtr recvNotification(const std::string &module);
    void saveMessageAndNotifyChange(NotificationMessagePtr notify);

    void eventHandler(std::stop_token stop_token);

    std::shared_ptr<SubscriberManager> subscribers_;

    std::mutex notification_message_lock_;
    std::atomic_flag synFlag_ = ATOMIC_FLAG_INIT;

    std::jthread event_handler_thread_; // consumer thread to handle notification message
    std::jthread notify_thread_; // producer thread to receive notification message and nofity consumer thread
};


#endif // JTHREAD_SAMPLE_

原先预计的是可以整一个无锁结构,后来专家的建议是锁+原子变量

#include "JthreadSample.h"

JthreadSample::JthreadSample()

{
}

JthreadSample::~JthreadSample()
{
    event_handler_thread_.request_stop();
    synFlag_.test_and_set();
    synFlag_.notify_one();
}

void JthreadSample::dispatch()
{
    threadForNotificationHandler();
    threadForEventHandler();
}



void JthreadSample::saveMessageAndNotifyChange(NotificationMessagePtr notify)
{
    {
        std::lock_guard lk{notification_message_lock_};
        notification_messages_.push(std::move(notify));
    }
    // set atomic flag to true and notify event handler thread
    synFlag_.test_and_set();
    synFlag_.notify_one();
}


static NotificationMessagePtr recvNotification(const std::string &module)
{
    return std::make_unique<NotificationMessage>(module);
  
}

void JthreadSample::receiveNotifications(std::stop_token &stop_token)
{
    std::string module{"hello you"};
    while (loopCondition(stop_token))
    {
        try
        {
            auto notify = recvNotification(module);
            if (notify != nullptr)
            {
                saveMessageAndNotifyChange(std::move(notify));
            }
        }
        catch (...)
        {
            // All sessions are not connected and can not receive anymore
            // Resubscribe needed.
            return;
        }
    }
}

void JthreadSample::notificationHandler(std::stop_token stop_token)
{
    while (loopCondition(stop_token))
    {
        receiveNotifications(stop_token);
    }
}

void JthreadSample::threadForNotificationHandler()
{
    notify_thread_ = std::jthread([this](std::stop_token token)
                                        {
                                            this->notificationHandler(token);
                                        });
}

bool JthreadSample::loopCondition(std::stop_token& stop_token)
{
    return !stop_token.stop_requested();
}


NotificationMessagePtr JthreadSample::readOneNotificationMessage()
{
    std::lock_guard lk{notification_message_lock_};

    auto msg = std::move(notification_messages_.front());
    notification_messages_.pop();

    return msg;
}

void JthreadSample::handleNotificationMessage()
{
    synFlag_.wait(false); // wait until notification thread notify, unblock if value is true.
    synFlag_.clear(); // set value to false

    while(notification_messages_.size())
    {
        auto msg = readOneNotificationMessage();
        //do something
        subscribers_->callEventHandler(msg->module);
    }
}

void JthreadSample::eventHandler(std::stop_token stop_token)
{
    while (loopCondition(stop_token))
    {
        handleNotificationMessage();
    }
}

void JthreadSample::threadForEventHandler()
{
    event_handler_thread_ = std::jthread([this](std::stop_token token)
                                         {
                                            this->eventHandler(token);
                                         });
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值