Ok, so there's three ways of doing this, one easy, two messy
Clean
The easy way runs something like this:
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
}
}
Of course this means your "abort" is no longer the user pressing CTRL-C, they just press the key 'c', or indeed any program that can write to this stdin can send a 'c'. Alternatively, you could also add another ZMQ socket as a command channel. There's no tolerance to signals at all here, but I've always found that mixing use of signals with Actor model programming is a very awkward thing to do. See below.
Messy
The messy way using signals looks something like this:
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>
}
}
Hybrid (Also Messy)
In the ZeroMQ guide documentation here they're sort of blending the two idea, by having a signal handler write to a pipe and including the pipe in the zmq_poll much as I have done above with stdin.
This is a common trick to turn asynchronous signals into synchronous events.
However there's no hint at all as to whether any of the zmq routines can be restarted. They're simply using it as a way to initiate a clean shutdown having abandoned any recv() or send() that are in progress. If in order to cleanly abort you need to finish off a sequence of recv() and send() routines then there's no guarantee that that is possible if signals are being used.
Forgive me if I'm wrong, but it feels like you are re-purposing SIGINT away from meaning "terminate the whole program immediately". If so it's likely that you'll be wanting to resuming your communications loop at a later time. In which case, who knows whether any of the recv() or send() calls are resumable after the arrival of your signal. There's a whole bunch of system calls that zmq will be using. Many of them are not-restartable under certain circumstances, and there's no telling how ZMQ has used these calls (short of reading their source code).
Conclusion
Basically I would simply steer clear of using signals altogether, especially as you don't want to install your own handler. By using stdin or a pipe or another ZMQ socket (or indeed all three) as an 'abort' channel included in zmq_poll() you would be providing a simple and effective means to abort your loop, and there would be no complications resulting from its use.