How to handle a Thread Issue in ZeroMQ + Ruby?
<p>Stumble upon reading <a href="http://zeromq.org/area:faq" rel="nofollow noreferrer">ZeroMQ FAQ</a> about a Thread safety.</p>

<blockquote>
  <p>My multi-threaded program keeps crashing in weird places inside the ZeroMQ library. What am I doing wrong?</p>
  
  <p>ZeroMQ sockets are <strong>not</strong> thread-safe. This is covered in some detail in the Guide.</p>
  
  <p>The short version is that sockets should not be shared between threads. We recommend creating a dedicated socket for each thread.</p>
  
  <p>For those situations where a dedicated socket per thread is infeasible, a socket may be shared if and only if each thread executes a full memory barrier before accessing the socket. Most languages support a Mutex or Spinlock which will execute the full memory barrier on your behalf. </p>
</blockquote>

<p>My multi-threaded program keeps crashing in weird places inside the ZeroMQ library.<br>
What am I doing wrong? </p>

<p>Following is my following code:</p>

<pre><code>Celluloid::ZMQ.init
module Scp
    module DataStore
    class DataSocket
        include Celluloid::ZMQ 
            def pull_socket(socket)
                @read_socket = Socket::Pull.new.tap do |read_socket|
                    ## IPC socket
                    read_socket.connect(socket)
                end
            end

            def push_socket(socket)
                @write_socket = Socket::Push.new.tap do |write_socket|
                    ## IPC socket
                    write_socket.connect(socket)
                end
            end

            def run
                pull_socket and push_socket and loopify!
            end

            def loopify!
                loop {
                   async.evaluate_response(read_socket.read_multipart)
                }
            end

            def evaluate_response(data)
                return_response(message_id,routing,Parser.parser(data))
            end

            def return_response(message_id,routing,object)
                data = object.to_response
                write_socket.send([message_id,routing,data])
            end
        end
    end
end  

DataSocket.new.run 
</code></pre>

<p>Now, there are couple things I'm unclear off:</p>

<p><strong>1)</strong>  Assuming that <code>async</code> spawns a new <code>Thread</code> ( every time ) and the <code>write_socket</code> is shared between the all threads and ZeroMQ says that their socket is not thread-safe. I certainly see the <code>write_socket</code> running into threads safety issue.<br>
( Btw, hasn't faced this issue in all end to end testing thus far. )</p>

<p><strong>Question 1</strong> : Is my understanding correct on this?</p>

<p>To solve this, ZeroMQ asks us to achieve this using Mutex, Semaphore.</p>

<p>Which results in <em>Question 2</em></p>

<p><strong>2)</strong>  Context Switching.</p>

<p>Given a threaded application can context switch anytime.
Looking at the ffi-rzmq code <code>Celluloid::ZMQ</code> <strong><code>.send()</code></strong> internally calls <a href="https://github.com/chuckremes/ffi-rzmq/blob/master/lib/ffi-rzmq/socket.rb#L263" rel="nofollow noreferrer">send_strings()</a>, which internally called <code>send_multiple()</code></p>

<p><strong>Question 2:</strong> Context Switching can happen ( anywhere ) inside ( even on critical section )  (here)[<a href="https://github.com/chuckremes/ffi-rzmq/blob/master/lib/ffi-rzmq/socket.rb#L510]" rel="nofollow noreferrer">https://github.com/chuckremes/ffi-rzmq/blob/master/lib/ffi-rzmq/socket.rb#L510]</a></p>

<p>This can also lead to a data ordering issue.</p>

<p>Is my following observation correct?</p>

<p><strong>Note:</strong> </p>

<pre><code>Operating system ( MacOS, Linux and CentOS )  
Ruby - MRI 2.2.2/2.3.0
</code></pre>