I'd like to pass a string argument to a child thread ( that is continuously reading a socket ) and call a setsockopt()
with that argument on that socket.
I'm using ZeroMQ sockets, so calling setsockopt()
is not threadsafe here, I'd call the setsockopt()
from the child thread ( as was recommended here ). An argument update would occur probably only once in billions of read cycles, and it feels a bit wrong to add an if
-structure to the child's every cycle like this:
bool new_arg_available;
std::string new_arg;
while(1){
sub_socket->recv(data); // . . . . . . a blocking method call
printData(data)
... // . . . . . . data can set new_arg_available
if (new_arg_available){ // . . . . . . synchronization goes here
sub_socket->setsockopt(ZMQ_SUBSCRIBE, new_arg, ... );
new_arg_available = false;
}
}
For me, the most straightforward would probably be either:
Add a mutex to the global namespace, lock it when a new_arg
available in the parent thread, and unlock it from the child thread.
use a std::atomic<bool>
and use it the same way as in 1.
However, what I would like to achieve somehow is to make the child interruptible, so that I could eliminate the if
-structure from the end of the while(){...}
block. I wouldn't mind the penalty of a context switch, because this event would be so seldom.
I'm relatively new to C++, and I would like to learn about best practices here, how to achieve this in an efficient way. I would like to solve it without using Boost, the only examples I could find to achieve interruptible threads were using Boost.
The primary remark on the ZeroMQ evangelisation is, that the ZeroMQ authors have advocated since ever to avoid any sort of sharing - Zero-sharing.
Given you already have instantiated the ZeroMQ infrastructure, better use an inter-thread PUSH/PULL
over the IO-thread-less inproc://
transport-class and forget about any tricky (b-)locking.
The one side ( the Injector ) just aPushCHANNEL.send( new_arg );
and the other ( the Implementor ) just either aPullCHANNEL.recv()
-s as needed / when needed, or may use smarter means of aPullCHANNEL.poll()
-testing, again best if using the Zero-wait form of the polling-test if aPullCHANNEL.poll( 0 ){...}else{...}
And your distributed-computing architecture becomes a fully decomposed, multi-agent role-based clean and smart, without having any dirty deadlocks ( so best forget REQ/REP
since beginning ), without any hard to trace/debug conceptual flaws and all errors get detected where applicable and where a local responsibility makes sense to map the root-cause of any such error for an on-the-fly due error-handling.
NB: Yes, ZeroMQ has been since ever designed without a need for a thread-safeness, as there was nothing left to be shared ( Zero-sharing ). Some recent efforts in API v4.1+ started to decline from this Zen-of-Zero, so one may read about some aspects of thread-safeness, yet as noted above and as present on almost every page of the fabulous Pieter HINTJENS' ZeroMQ bible-book - "Code Connected, Volume 1" - best share nothing.
The ZeroMQ design is fully asynchronous and requires no care for locking, mutex-gymnastics and other forms of extrinsically introduced elements in an otherwise clean and smart multi-agent async signalling / messaging based distributed-computing architecture. You will fall in love with it, so keep trying and read the book. It will be hard, yet it will pay a lot for those, who will carry on and find the beauty of ZeroMQ Zen-of-Zero.