Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Poll monitoring sockets #109

Open
v1bri opened this issue Jan 18, 2017 · 4 comments
Open

Poll monitoring sockets #109

v1bri opened this issue Jan 18, 2017 · 4 comments

Comments

@v1bri
Copy link

v1bri commented Jan 18, 2017

I would like to be able to use zmq::poll() for normal ZMQ sockets and monitoring ZMQ sockets, to handle them all within a single thread. However this isn't currently possible with the zmq::monitor_t class due to the blocking nature of the zmq::monitor_t::monitor() method and the lack of an accessor for the socket that is monitoring socketPtr.

Could we augment the zmq::monitor_t class with the functionality to allow polling? Perhaps something like the following would work (apologies in advance for syntax)...

class monitor_t {
    // ...
    inline operator void* () ZMQ_NOTHROW
    {
        return monitorPtr;
    }

    inline operator void const* () const ZMQ_NOTHROW
    {
        return monitorPtr;
    }

    void monitor_start(socket_t &socket, const char *addr_, int events = ZMQ_EVENT_ALL)
    {
        int rc = zmq_socket_monitor(socket.ptr, addr_, events);
        if (rc != 0)
            throw error_t ();

        socketPtr = socket.ptr;
        monitorPtr = zmq_socket (socket.ctxptr, ZMQ_PAIR);
        assert (monitorPtr);

        rc = zmq_connect (monitorPtr, addr_);
        assert (rc == 0);

        on_monitor_started();
    }

    bool monitor_poll()
    {
        zmq_msg_t eventMsg;
        zmq_msg_init (&eventMsg);
        int rc = zmq_msg_recv (&eventMsg, s, 0);
        if (rc == -1 && zmq_errno() == ETERM)
            return false;
        assert (rc != -1);

        // ...
    }

    void monitor(socket_t &socket, const char *addr_, int events = ZMQ_EVENT_ALL)
    {
        monitor_start(socket, addr_, events);

        bool keep_looping = monitor_poll();
        while (keep_looping) {
            keep_looping = monitor_poll();
        }
    }
    // ...

private:
    void* socketPtr;
    void* monitorPtr;
};

This would allow a usage similar to the following...

void Worker(zmq::socket_t* raw_zmq_data_sock)
{
    std::unique_ptr<zmq::socket_t> zmq_data_sock(raw_zmq_data_sock);
    std::unique_ptr<zmq::monitor_t> zmq_monitor_sock(new zmq::monitor_t);

    zmq_monitor_sock->start_monitor(*zmq_data_sock, "inproc://abc");

    std::vector<zmq::pollitem_t> poll_items = {
        { (void*)(*zmq_data_sock), 0, ZMQ_POLLIN | ZMQ_POLLERR, 0, },
        { (void*)(*zmq_monitor_sock), 0, ZMQ_POLLIN | ZMQ_POLLERR, 0, },
    };

    while (true) {
        poll_items[0].revents = 0;
        poll_items[1].revents = 0;
        items = zmq::poll(poll_items);

        // ...
        if (poll_items[1].revents) {
            zmq_monitor_sock->monitor_poll();
        }
    }

    // ...
}

I can put a pull request together if it sounds like a reasonable idea.

@a4z
Copy link
Contributor

a4z commented Jul 16, 2017

I have just split the blocking function without breaking the existing interface.
b838563
now you can use monitor_t non blocking in the same thread as the monitored, or any other, socket.

the socket is currently not public, but I have a similar use case like you describe and might adopt it to be able to poll on the monitor and other socket in one poll item. But before I do this I would like to measure if this has a performance advantage over having 2 poll items.

Implicit conversion, like you suggest, is imho not like it should be in C++ since C++ should be type safe and strong typed.
also, I do not think that the sockets currently stored as void pointers it the best idea, so I think they should be typed.

@lp35
Copy link

lp35 commented May 13, 2020

Hey,

I'm also missing this feature. Why not making monitor_t inherit from socket_t?

IMHO, this would be a better RAII design (see #381), and force the user to configure the monitor in the constructor instead of using init() method.

@sigiesec
Copy link
Member

I'm also missing this feature. Why not making monitor_t inherit from socket_t?

I think it is not necessary, it would be sufficient if a method were added to monitor_t that provides accessing to its _monitor_socket, IIUC. Composition should generally be preferred over inheritance.

IMHO, this would be a better RAII design (see #381), and force the user to configure the monitor in the constructor instead of using init() method.

I agree that the init method is not nice, however bear in mind that any changes need to be backwards-compatible. It is conceivable to add a new class under a different name that is designed without an ìnitmethod and declaremonitor_t` deprecated.

@dietelTiMaMi
Copy link
Contributor

I added a Pull Request (#612) to expose the monitor socket for using it with an active poller from the hppaddon.cpp
the check_event() method was split to prevent polling for the same event twice.
The api stays fully backward compatible.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants