class_docstr: A base thread to communicate with all SimulatorProcess.
  It should produce action for each simulator, as well as
  defining callbacks when a transition or an episode is finished.
class_docstr_tok: ["A","base","thread","to","communicate","with","all","SimulatorProcess",".","It","should","produce","action","for","each","simulator",",","as","well","as","defining","callbacks","when","a","transition","or","an","episode","is","finished","."]
code: def run(self):
      self.clients = defaultdict(self.ClientState)
      try:
          while True:
              msg = loads(self.c2s_socket.recv(copy=False))
              ident, state, reward, isOver = msg
              client = self.clients[ident]
              if client.ident is None:
                  client.ident = ident
              # maybe check history and warn about dead client?
              self._process_msg(client, state, reward, isOver)
      except zmq.ContextTerminated:
          logger.info("[Simulator] Context was terminated.")
  
imports: import multiprocessing
  import os
  import threading
  import time
  from abc import ABCMeta, abstractmethod
  from collections import defaultdict
  import six
  import zmq
  from six.moves import queue
  from tensorpack.utils import logger
  from tensorpack.utils.concurrency import LoopThread, enable_death_signal, ensure_proc_terminate
  from tensorpack.utils.serialize import dumps, loads
label_desc: Use image node_id 2 for calling the SimulatorMaster obj's underlying member method code with example usage: obj.run() without return types