注意: This question非常接近我的,但我至少可以使用一些工作示例来提供解决方案,也许SELECT DISTINCT
tew_cable.cab_tag,
CASE
WHEN L1_From.loc_loc_id = L2_From.loc_id
THEN L1_From.loc_text
END AS Rack_From,
CASE
WHEN L1_From.loc_loc_id = L2_From.loc_id
THEN L2_From.loc_text
ELSE L1_From.loc_text
END AS Compartment_From,
CASE
WHEN C1_From.com_com_id = C2_From.com_id
THEN C1_From.com_tag
END AS PP_From,
CASE
WHEN C1_From.com_com_id = C2_From.com_id
THEN SUBSTRING(com_tag, 1, CHARINDEX('\', com_tag)-1)
END AS PP_From_INDEX,
CASE
WHEN C1_From.com_com_id = C2_From.com_id
THEN LEFT(C1_From.com_tag,2)
END AS PP_From_CHOP,
CASE
WHEN C1_From.com_com_id = C2_From.com_id
THEN C2_From.com_tag
ELSE C1_From.com_tag
END AS Component_From
FROM tew_cable
LEFT JOIN tew_location AS L1_From
LEFT JOIN tew_location AS L2_From
ON L1_From.loc_loc_id = L2_From.loc_id
ON tew_cable.cab_loc_id_from = L1_From.loc_id
INNER JOIN tew_cablewire
ON tew_cable.cab_id=tew_cablewire.caw_cab_id
LEFT JOIN tew_wire
ON tew_cablewire.caw_cab_id = tew_wire.wir_cab_id
AND tew_cablewire.caw_no = tew_wire.wir_caw_no
LEFT JOIN tew_component AS C1_From
LEFT JOIN tew_component AS C2_From
ON C1_From.com_com_id = C2_From.com_id
ON C1_From.com_id = tew_wire.wir_com_idfrom
带来一些魔力我只是不知道。
目前我对阻止ZeroMQ
调用的异常做出反应,如下所示:
ZeroMQ
我的意图是:重新抛出所有捕获的异常,但是由中断的系统调用触发的异常,我通常忽略(例如 {{1 }} ),然后重新启动try {
zmq::poll(&items, number, timeout);
} catch (zmq::error_t &ex) {
if (ex.num() != EINTR) {
throw;
}
}
...
。
如果 SIGPROF
(CTRL-C)我想以不同的方式进行(例如,还要重新抛出或终止循环)。
目前我最好的办法是安装一个听 zmq::poll
的信号处理程序,但由于SIGINT
自己捕获信号,我更喜欢更复杂的方法。
答案 0 :(得分:1)
如果我正确地阅读了原始海报的问题,@ frans会询问是否有办法重新抛出某些异常,其中C ++异常包含EINTR
错误代码,除了那些由某些信号。 @frans目前有一个SIGINT
信号处理程序,并想知道是否有更清洁的方式。
提出了两个不同的问题,关于POSIX signal()
处理及其与C ++异常的交互:
zmq::error_t
是由zmq::poll()
生成的C ++异常,是系统调用返回EINTR
的结果。TL; DR回答:不,没有更清洁的方式。
libzmq
似乎没有安装自己的信号处理程序,但如果基础系统调用中断,它会抛出zmq::error_t
EINTR
(即poll()
返回-1,errno
被复制到zmq::error_t
异常。)这可能意味着POSIX信号已经被传递并且特定于进程的处理程序运行,但还有其他原因。
POSIX / Unix / Linux / BSD signal()
是一个操作系统工具,它指示内核中发生了异常。进程可以选择安装自己的处理程序以从情境中恢复,例如,SIGINT
和SIGQUIT
处理程序关闭文件描述符,执行各种类型的清理等。这些处理程序位于 no方式与C ++异常处理有关。
其他警告:不要从POSIX / Unix / Linux / BSD信号处理程序中抛出C ++异常。这是先前讨论的in this SO topic。
答案 1 :(得分:0)
好的,所以有三种方法可以做到这一点,一种是简单的,两种是凌乱的
<强>清洁强>
简单的方法就是这样:
zmq::socket_t inSock;
zmq::pollitem_t pollOnThese[2];
int quitLoop = 0;
<code to connect inSock to something>
pollOnThese[0].socket = NULL; // This item is not polling a ZMQ socket
pollOnThese[0].fd = 0; // Poll on stdin. 0 is the fd for stdin
pollOnThese[0].event = ZMQ_POLLIN;
pollOnThese[1].socket = &inSock; // This item polls inSock
pollOnThese[1].fd = 0; // This field is ignored because socket isn't NULL
pollOnThese[1].event = ZMQ_POLLIN;
while (!quitLoop)
{
zmq::poll(pollOnThese,2);
if (pollOnThese[0].revents == ZMQ_POLLIN)
{
// A key has been pressed, read it
char c;
read(0, &c, 1);
if (c == 'c')
{
quitloop = 1;
}
}
if (pollOnThese[1].revent == ZMQ_POLLIN)
{
// Handle inSock as required
}
}
当然这意味着你的“中止”不再是用户按下CTRL-C,他们只需按下'c'键,或者任何可以写入此stdin的程序都可以发送'c'。或者,您也可以添加另一个ZMQ套接字作为命令通道。这里根本没有对信号的容忍度,但我总是发现将信号与Actor模型编程混合使用是一件非常尴尬的事情。见下文。
<强>凌乱强>
使用信号的混乱方式看起来像这样:
zmq::socket_t inSock;
zmq::pollitem_t pollOnThis;
int quitLoop = 0;
<code to connect inSock to something>
<install a signal handler that handles SIGINT by setting quitLoop to 1>
pollOnThis.socket = &inSock; // This item polls inSock
pollOnThis.fd = 0; // This field is ignored because socket isn't NULL
pollOnThis.event = ZMQ_POLLIN;
while (!quitLoop)
{
try
{
zmq::poll(&pollOnThis, 1);
}
catch (zmq::error_t &ex)
{
if (ex.num() != EINTR)
{
throw;
}
}
if (pollOnThis.revent == ZMQ_POLLIN && !quitLoop)
{
// Handle inSock as required
bool keepReading = true;
do
{
try
{
inSock.recv(&message)
keepReading = false;
}
catch (zmq::error_t &ex)
{
if (ex.num() != EINTR)
{
throw;
}
else
{
// We also may want to test quitFlag here because the signal,
// being asynchronous, may have been delivered mid recv()
// and the handler would have set quitFlag.
if (quitFlag)
{
// Abort
keepReading = false;
}
else
{
// Some other signal interrupted things
// What to do? Poll has said a message can be read without blocking.
// But does EINTR mean that that meassage has been partially read?
// Has one of the myriad of system calls that underpin recv() aborted?
// Is the recv() restartable? Documentation doesn't say.
// Have a go anyway.
keepReading = true;
}
} // if
} // catch
}
while (keepReading);
<repeat this loop for every single zmq:: recv and zmq::send>
}
}
混合(也是凌乱)
在ZeroMQ指南文档here中,通过让信号处理程序写入管道并在zmq_poll中包含管道,就像我上面用stdin所做的那样,它们混合了这两个想法。
这是将异步信号转换为同步事件的常见技巧。
然而,关于是否可以重新启动任何zmq例程,根本没有任何提示。他们只是使用它作为一种方法来启动干净关闭,放弃了正在进行的任何recv()或send()。如果为了彻底中止你需要完成一系列recv()和send()例程,那么无法保证在使用信号时这是可能的。
如果我错了,请原谅我,但感觉你正在重新使用SIGINT,而不是“立即终止整个程序”。如果是这样,您可能希望稍后恢复通信循环。在这种情况下,谁知道在信号到达后是否可以恢复任何recv()或send()调用。 zmq将使用一大堆系统调用。其中许多都是not-restartable under certain circumstances,并且没有人知道ZMQ如何使用这些调用(缺少阅读源代码)。
<强>结论强>
基本上我只是避免完全使用信号,特别是因为你不想安装自己的处理程序。通过使用stdin或管道或其他ZMQ套接字(或实际上所有三个)作为zmq_poll()中包含的“中止”通道,您将提供一种简单有效的方法来中止您的循环,并且不会因此而导致并发症使用。
答案 2 :(得分:0)
我遇到了类似的问题,并且长期盯着这个问题及其答案,希望如果我足够努力地凝视,一个解决方案将会神奇地出现。
最后,我采用了方法detailed in this article。
最重要的是,我们需要一个基于ppoll
或更确切地说pselect
的ZMQ轮询机制(我实现了一种,但是我仍然需要将其放在单独的库中)。这些p-
变体将信号掩码作为附加参数。他们设置信号掩码,运行常规的poll
/ select
,然后将信号掩码重置为其先前状态。这意味着在ppoll
/ pselect
之外,您可以阻止所有期望的信号(阻止它们会导致它们在操作系统中排队,不会丢失),然后仅在{ {1}} / poll
。
这实际上是在您的轮询器中添加一个“信号套接字”。当轮询器从实际的套接字接收到信号时,轮询器将返回(带有select
),或者当被允许通过使用信号掩码将其中断的信号中断时,则返回(带有0
)。您可以使用信号处理程序来设置一些标志。
现在,在进行轮询调用之后,通常当您通常通过现在可以读取/写入的套接字时,首先要检查从信号处理程序设置的标志。信号在-1
/ ppoll
之外的任何地方都被阻止,因此可以肯定地知道,除了此处以外,您无需检查此标志。这样可以非常干净,紧凑且可靠地处理EINTR。
一些警告:要使其正常工作,您不能使用任何其他阻止调用,因此您的所有pselect
和send
都应处于非阻止状态(recv
标志)。 / p>
另一件事是what you already mentioned:在使用库的情况下,用户应可以自由安装自己的信号处理程序。因此,如果他们想以健壮的方式使用您的库,可能需要指导用户如何以这种方式正确处理信号。我认为,如果将标志(或翻转它的函数)展示给用户,以便他们可以从自己的信号处理程序中调用它,那应该是可行的。