8
votes

EDIT: solved myself, see below (although I'm not sure if I've stumbled upon a bug here)

Using the simple hello-world request-reply example below, closing the context at the end of the program fails: Either it simply hangs at ctx.close() or it throws the following exception:

Exception in thread "reaper-1" java.lang.NullPointerException
    at zmq.Ctx.destroy_socket(Ctx.java:327)
    at zmq.ZObject.destroy_socket(ZObject.java:144)
    at zmq.SocketBase.check_destroy(SocketBase.java:938)
    at zmq.SocketBase.start_reaping(SocketBase.java:753)
    at zmq.Reaper.process_reap(Reaper.java:133)
    at zmq.ZObject.process_command(ZObject.java:114)
    at zmq.Reaper.in_event(Reaper.java:90)
    at zmq.Poller.run(Poller.java:233)
    at java.lang.Thread.run(Thread.java:724)

Either way, the program does not halt.

Here is the code (please note that the sockets are both closed within the threads that create them):

import org.zeromq.ZMQ;
import org.zeromq.ZContext;

public class App {
    public static void main(String[] args) throws InterruptedException {
        final ZContext ctx = new ZContext();

        final Thread t1 = new Thread() {
            @Override
            public void run() {
                ZMQ.Socket socket = ctx.createSocket(ZMQ.REQ);
                socket.connect("inproc://test");
                System.err.format("[Thread %s] socket connected%n", Thread.currentThread().getId());
                socket.send("hello");
                System.err.format("[Thread %s] hello sent%n", Thread.currentThread().getId());
                String result = socket.recvStr();
                System.err.format("[Thread %s] received response '%s'%n", Thread.currentThread()
                        .getId(), result);
                socket.close();
                System.err.format("[Thread %s] socket closed%n", Thread.currentThread().getId());
                ctx.destroySocket(socket);
                System.err.format("[Thread %s] socket destroyed%n", Thread.currentThread().getId());
            }
        };
//      t1.start();

        final Thread t2 = new Thread() {
            @Override
            public void run() {
                ZMQ.Socket socket = ctx.createSocket(ZMQ.REP);
                socket.setLinger(10000);
                socket.bind("inproc://test");
                System.err.format("                    [Thread %s] socket bound%n", Thread.currentThread().getId());
                String request = socket.recvStr();
                assert request == "hello";
                System.err.format("                    [Thread %s] received request '%s'%n", Thread.currentThread()
                        .getId(), request);
                socket.send("world");
                socket.close();
                System.err.format("                    [Thread %s] socket closed%n", Thread.currentThread().getId());
                ctx.destroySocket(socket);
                System.err.format("                    [Thread %s] socket destroyed%n", Thread.currentThread().getId());
            }
        };
        t2.start();
        Thread.sleep(2000);
        t1.start();

        System.err.println("waiting on the threads to finish...");
        t1.join();
        t2.join();

        System.err.println("closing context...");
        ctx.close();
    }
}

EDIT: solved

It turns out that socket.close() does not work, and that ctx.destroySocket(socket) alone suffices (it also closes the socket). So removing socket.close() resolves the issue. Is this a bug?

2

2 Answers

4
votes

Had the same issue; it's not a bug, use one or the other, not both, but use the ZContext methods, they're more efficient.

close() explicitly closes the socket, so calling ctx.destroySocket() afterwards throws that exception. If you need to close the socket, use ctx.destroySocket(), don't use close() at all, and always use ctx.destroy() to close the context before shutting down and exiting gracefully, it will automatically close any sockets created from that context.

3
votes

I also had a similar problem, and after some surfing I found a discussion about related topics on JeroMQ (java implementation of ZMQ)'s Github site.

https://github.com/zeromq/jeromq/issues/40

It would seem that ZMQ.Context is part of a low level API, while ZContext is a higher level API. Consequently, context.close should not be used with ZContext, while ctx.destroySocket() should. And I'm sure there are a host of other similar issues one should know about.