Skip to main content
added 114 characters in body
Source Link
Loki Astari
  • 97.7k
  • 5
  • 126
  • 341

A reactor should hold a thread pool (or a single thread to do the work). When an event is triggered a thread is released from the pool and simply calls the OnMessage() method of all appropriately registered handlers.

                    std::this_thread::sleep_for(wait_for_input); // Simulate waiting for input, based on the message type, by putting the thread to sleep.

You should be using std::condition_variable. This allows you to sleep the thread so it does not use any resources until there is work for it to do. Then you can wake it up with a call to notify().

A reactor should hold a thread pool. When an event is triggered a thread is released from the pool and simply calls the OnMessage() method of all appropriately registered handlers.

                    std::this_thread::sleep_for(wait_for_input); // Simulate waiting for input, based on the message type, by putting the thread to sleep.

A reactor should hold a thread pool (or a single thread to do the work). When an event is triggered a thread is released from the pool and simply calls the OnMessage() method of all appropriately registered handlers.

                    std::this_thread::sleep_for(wait_for_input);

You should be using std::condition_variable. This allows you to sleep the thread so it does not use any resources until there is work for it to do. Then you can wake it up with a call to notify().

added 106 characters in body
Source Link
Loki Astari
  • 97.7k
  • 5
  • 126
  • 341

I have added some Pseudo code at the bottom to show an approximation of how the pattern should be written.

namespace ThorsAnvil::Reactor 
{

enum MessageTypes
{
    OPEN = 0,
    READ,       
    WRITE,
    CLOSE,
    REGISTER_HANDLER,
    REMOVE_HANDLER
};

class IEventHandler
{
    public:
        virtual ~IEventHandler() {};
        virtual void OnMessage(Message const& msg) = 0;
};

class Reactor
{
    // In more modern C++ I would not even use this.
    // Simply leave this out and use `std::async below.
    SimpleWorkQueue   threadPool;

    std::map<MessageTypes, std::list<std::unique_ptr<IEventHandler>>>  handler;

    public:
        addHandler(MessageTypes type, std::unique_ptr<IEventHandler> handler)
        {
            // Lock Here.
            handler[type].emplace_back(std::move(handler));
        }
        addEvent(MessageTypes type, Message const& event)
        {
            // Lock Here.
            auto& listHandlers = handler[type];
            for (auto const& handler: listHandlers) {
                // If you are not using the thread pool
                // replace this with std::async.
                threadPool.addWorkItem([&event, &handler]()
                {
                    handler->OnMessage(event);
                });
            }
        }
};
} // end of namespace
namespace ThorsAnvil::Reactor 
{

enum MessageTypes
{
    OPEN = 0,
    READ,       
    WRITE,
    CLOSE,
    REGISTER_HANDLER,
    REMOVE_HANDLER
};

class IEventHandler
{
    public:
        virtual ~IEventHandler() {};
        virtual void OnMessage(Message const& msg) = 0;
};

class Reactor
{
    SimpleWorkQueue   threadPool;

    std::map<MessageTypes, std::list<std::unique_ptr<IEventHandler>>>  handler;

    public:
        addHandler(MessageTypes type, std::unique_ptr<IEventHandler> handler)
        {
            // Lock Here.
            handler[type].emplace_back(std::move(handler));
        }
        addEvent(MessageTypes type, Message const& event)
        {
            // Lock Here.
            auto& listHandlers = handler[type];
            for (auto const& handler: listHandlers) {
                threadPool.addWorkItem([&event, &handler]()
                {
                    handler->OnMessage(event);
                });
            }
        }
};
} // end of namespace

I have added some Pseudo code at the bottom to show an approximation of how the pattern should be written.

namespace ThorsAnvil::Reactor 
{

enum MessageTypes
{
    OPEN = 0,
    READ,       
    WRITE,
    CLOSE,
    REGISTER_HANDLER,
    REMOVE_HANDLER
};

class IEventHandler
{
    public:
        virtual ~IEventHandler() {};
        virtual void OnMessage(Message const& msg) = 0;
};

class Reactor
{
    // In more modern C++ I would not even use this.
    // Simply leave this out and use `std::async below.
    SimpleWorkQueue   threadPool;

    std::map<MessageTypes, std::list<std::unique_ptr<IEventHandler>>>  handler;

    public:
        addHandler(MessageTypes type, std::unique_ptr<IEventHandler> handler)
        {
            // Lock Here.
            handler[type].emplace_back(std::move(handler));
        }
        addEvent(MessageTypes type, Message const& event)
        {
            // Lock Here.
            auto& listHandlers = handler[type];
            for (auto const& handler: listHandlers) {
                // If you are not using the thread pool
                // replace this with std::async.
                threadPool.addWorkItem([&event, &handler]()
                {
                    handler->OnMessage(event);
                });
            }
        }
};
} // end of namespace
added 1308 characters in body
Source Link
Loki Astari
  • 97.7k
  • 5
  • 126
  • 341

How to do it:

Re-Using a thread queue from here: A simple Thread Pool

namespace ThorsAnvil::Reactor 
{

enum MessageTypes
{
    OPEN = 0,
    READ,       
    WRITE,
    CLOSE,
    REGISTER_HANDLER,
    REMOVE_HANDLER
};

class IEventHandler
{
    public:
        virtual ~IEventHandler() {};
        virtual void OnMessage(Message const& msg) = 0;
};

class Reactor
{
    SimpleWorkQueue   threadPool;

    std::map<MessageTypes, std::list<std::unique_ptr<IEventHandler>>>  handler;

    public:
        addHandler(MessageTypes type, std::unique_ptr<IEventHandler> handler)
        {
            // Lock Here.
            handler[type].emplace_back(std::move(handler));
        }
        addEvent(MessageTypes type, Message const& event)
        {
            // Lock Here.
            auto& listHandlers = handler[type];
            for (auto const& handler: listHandlers) {
                threadPool.addWorkItem([&event, &handler]()
                {
                    handler->OnMessage(event);
                });
            }
        }
};
} // end of namespace

How to do it:

Re-Using a thread queue from here: A simple Thread Pool

namespace ThorsAnvil::Reactor 
{

enum MessageTypes
{
    OPEN = 0,
    READ,       
    WRITE,
    CLOSE,
    REGISTER_HANDLER,
    REMOVE_HANDLER
};

class IEventHandler
{
    public:
        virtual ~IEventHandler() {};
        virtual void OnMessage(Message const& msg) = 0;
};

class Reactor
{
    SimpleWorkQueue   threadPool;

    std::map<MessageTypes, std::list<std::unique_ptr<IEventHandler>>>  handler;

    public:
        addHandler(MessageTypes type, std::unique_ptr<IEventHandler> handler)
        {
            // Lock Here.
            handler[type].emplace_back(std::move(handler));
        }
        addEvent(MessageTypes type, Message const& event)
        {
            // Lock Here.
            auto& listHandlers = handler[type];
            for (auto const& handler: listHandlers) {
                threadPool.addWorkItem([&event, &handler]()
                {
                    handler->OnMessage(event);
                });
            }
        }
};
} // end of namespace
Source Link
Loki Astari
  • 97.7k
  • 5
  • 126
  • 341
Loading