我想知道如何正确关闭JeroMQ,到目前为止我知道三种方法都有其优点和缺点,我不知道哪一种是最好的。
情况:
我目前的方法:
主题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脱离其阻塞状态,共享套接字或终止整个上下文。
这样做的正确方法是什么?
答案 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 - 线程通过连接的套接字进行通信,而不是共享一个套接字的同一端。不需要像共享布尔停止变量这样的东西。