JeroMQ正确关闭

时间:2014-03-27 11:46:26

标签: sockets zeromq recv jeromq

我想知道如何正确关闭JeroMQ,到目前为止我知道三种方法都有其优点和缺点,我不知道哪一种是最好的。

情况:

  • 线程A:拥有上下文,应提供启动/停止方法
  • 线程B:实际侦听器线程

我目前的方法:

主题A

static ZContext CONTEXT = new ZContext();
Thread thread;

public void start() {
    thread = new Thread(new B()).start();
}

public void stop() {
    thread.stopping = true;
    thread.join();
}

主题B

boolean stopping = false;
ZMQ.Socket socket;

public void run() {
    socket = CONTEXT.createSocket(ROUTER);
    ... // socket setup
    socket.setReceiveTimeout(10);

    while (!stopping) {
        socket.recv();
    }

    if (NUM_SOCKETS >= 1) {
        CONTEXT.destroySocket(socket);
    } else {
        CONTEXT.destroy();
    }
}

这很有用。关机10ms对我来说没有问题,但是当没有收到消息时,我会不必要地增加CPU负载。目前我更喜欢这个。


第二种方法在两个线程之间共享套接字:

主题A

static ZContext CONTEXT = new ZContext();
ZMQ.Socket socket;
Thread thread;

public void start() {
    socket = CONTEXT.createSocket(ROUTER);
    ... // socket setup
    thread = new Thread(new B(socket)).start();
}

public void stop() {
    thread.stopping = true;
    CONTEXT.destroySocket(socket);
}

主题B

boolean stopping = false;
ZMQ.Socket socket;

public void run() {
    try {
        while (!stopping) {
            socket.recv();
        }
    } catch (ClosedSelection) {
        // socket closed by A
        socket = null;
    }
    if (socket != null) {
        // close socket myself
        if (NUM_SOCKETS >= 1) {
            CONTEXT.destroySocket(socket);
        } else {
            CONTEXT.destroy();
        }
    }
}

也像魅力一样工作,但即使recv已经阻止异常也不会被抛出。如果我在启动线程A后等待一毫秒,则始终抛出异常。我不知道这是一个错误还是仅仅是我滥用的影响,因为我共享了套接字。


“revite”之前(https://github.com/zeromq/jeromq/issues/116)问了这个问题并得到了第三个解决方案: https://github.com/zeromq/jeromq/blob/master/src/test/java/guide/interrupt.java

要点: 他们调用ctx.term()并在socket.recv()中断线程阻塞。

这很好,但我不想终止我的整个上下文,只是这个单个套接字。我必须为每个插槽使用一个上下文,所以我无法使用inproc。

摘要

目前我不知道除了使用超时之外如何让线程B脱离其阻塞状态,共享套接字或终止整个上下文。

这样做的正确方法是什么?

3 个答案:

答案 0 :(得分:4)

经常提到你可以破坏zmq上下文,并且共享该上下文的任何东西都会退出,但是这会产生一场噩梦,因为你现有的代码必须尽力避免意外调用死套接字对象的雷区。 / p>

尝试关闭套接字不起作用,因为它们不是线程安全的,并且您最终会崩溃。

答案:最好的方法是按照ZeroMQ指南建议通过多线程进行任何使用;使用zmq套接字而不是线程互斥/锁/等。设置一个额外的侦听器套接字,您将在关闭时连接并发送一些内容,并且您的run()应使用JeroMQ Poller检查您的两个套接字中的哪一个接收任何内容 - 如果附加套接字收到某些内容然后退出。 / p>

答案 1 :(得分:3)

老问题,但以防万一......

我建议您查看ZThread source。您应该能够创建 IAttachedRunnable 的实例,您可以将其传递给 fork 方法,并且实例的run方法将传递给PAIR套接字并在另一个套接字中执行线程,而 fork 将返回连接的PAIR套接字,用于与 IAttachedRunnable 获得的PAIR套接字进行通信。

答案 2 :(得分:1)

查看jeromq源here,即使你正在进行“阻塞”recv,你仍然在整个时间内烧掉CPU(线程永远不会睡觉)。如果你担心这一点,让第二个线程在轮询之间休眠并让父线程中断。像(只是相关部分)的东西:

主题A

public void stop() {
    thread.interrupt();
    thread.join();
}

主题B

while (!Thread.interrupted()) {
  socket.recv(); // do whatever
  try {
    Thread.sleep(10); //milliseconds
  } catch (InterruptedException e) {
    break;
  }
}

另外,关于你的第二个解决方案,一般来说你不应该在线程之间共享套接字 - zeromq guide非常明确 - “不要在线程之间共享ØMQ套接字.ØMQ套接字不是线程安全的。 “请记住,ZMQ的主要用途是IPC - 线程通过连接的套接字进行通信,而不是共享一个套接字的同一端。不需要像共享布尔停止变量这样的东西。