How to handle a Thread Issue in ZeroMQ + Ruby?

前端 未结 2 957
悲&欢浪女
悲&欢浪女 2020-12-10 16:02

Stumble upon reading ZeroMQ FAQ about a Thread safety.

My multi-threaded program keeps crashing in weird places inside the ZeroMQ library. What am I d

2条回答
  •  予麋鹿
    予麋鹿 (楼主)
    2020-12-10 16:30

    This answer isn't a good solution to your problem, and definitely go with what user3666197 suggests. I think this solution has potential to work, but also at a large scale there may be performance costs due to mutex congestion.

    Question 1: Assuming that async spawn new Thread(every time) and write_socket is shared between the all threads and zeromq says that their socket is not threaded safe. I certainly see write_socket running into threads safety issue. (Btw hasn't faced this issue in all end to end testing thus far.) Is my understanding correct on this?

    From my understanding of the documentation, yes, this could be an issue because the sockets are not thread safe. Even if you are not experiencing the issue, it could pop up later.

    Question 2: Context Switching can happen(anywhere) inside(even on critical section)

    Yes, so one way we could potentially get around this is with a mutex/semaphore to make sure we don't have a context switch happen at the wrong time.

    I would do something like this, but there might be a slightly better approach depending on what methods being called are not thread safe:

    Celluloid::ZMQ.init
    module Scp
      module DataStore
        class DataSocket
          include Celluloid::ZMQ
    
          def initialize
            @mutex = Mutex.new
          end
    
          def pull_socket(socket)
            Thread.new do
              @mutex.synchronize do
                @read_socket = Socket::Pull.new.tap do |read_socket|
                  ## IPC socket
                  read_socket.connect(socket)
                end
              end
            end.join
          end
    
          def push_socket(socket)
            Thread.new do
              @mutex.synchronize do
                @write_socket = Socket::Push.new.tap do |write_socket|
                  ## IPC socket
                  write_socket.connect(socket)
                end
              end
            end.join
          end
    
          def run
            # Missing socket arguments here
            pull_socket and push_socket and loopify!
          end
    
          def loopify!
            Thread.new do
              @mutex.synchronize do
                loop {
                  async.evaluate_response(read_socket.read_multipart)
                }
              end
            end.join
          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
    

提交回复
热议问题