docs: def start_monitoring(self):
          """
          Monitor IP addresses and send notifications if one of them has failed.
  
          This function will continuously monitor q_monitor_ips for new lists of
          IP addresses to monitor. Each message received there is the full state
          (the complete lists of addresses to monitor).
  
          Push out (return) any failed IPs on q_failed_ips. This is also a list
          of IPs, which may be empty if all instances work correctly.
  
          If q_monitor_ips receives a 'None' instead of list then this is
          intepreted as a stop signal and the function exits.
  
          """
          time.sleep(1)
  
          # This is our working set. This list may be updated occasionally when
          # we receive messages on the q_monitor_ips queue. But irrespective of
          # any received updates, the list of IPs in here is regularly checked.
          list_of_ips                = []
  
          currently_failed_ips       = set()
          currently_questionable_ips = set()
  
          # Accumulating failed IPs for 10 intervals before rechecking them to
          # see if they are alive again
          recheck_failed_interval = 10
  
          try:
              interval_count = 0
              while not CURRENT_STATE._stop_all:
                  start_time = time.time()
                  # See if we should update our working set
                  new_ips = self.get_new_working_set()
                  if new_ips:
                      list_of_ips = new_ips
                      # Update the currently-failed-IP list to only include IPs
                      # that are still in the spec. The list update may have
                      # removed some of the historical, failed IPs altogether.
                      currently_failed_ips = \
                              set([ip for ip in currently_failed_ips
                                   if ip in list_of_ips])
                      # Same for the questionable IPs
                      currently_questionable_ips = \
                              set([ip for ip in currently_questionable_ips
                                   if ip in list_of_ips])
  
                  # Don't check failed IPs for liveness on every interval. We
                  # keep a list of currently-failed IPs for that purpose.
                  # But we will check questionable IPs, so we don't exclude
                  # those.
                  live_ips_to_check = [ip for ip in list_of_ips if
                                       ip not in currently_failed_ips]
                  logging.debug("Checking live IPs: %s" %
                                (",".join(live_ips_to_check)
                                 if live_ips_to_check else "(none alive)"))
  
                  # Independent of any updates: Perform health check on all IPs
                  # in the working set and send messages out about any failed
                  # ones as necessary.
                  if live_ips_to_check:
                      failed_ips, questionable_ips = \
                                      self.do_health_checks(live_ips_to_check)
                      if failed_ips:
                          # Update list of currently failed IPs with any new ones
                          currently_failed_ips.update(failed_ips)
                          logging.info('Currently failed IPs: %s' %
                                       ",".join(currently_failed_ips))
                          # Let the main loop know the full set of failed IPs
                          self.q_failed_ips.put(list(currently_failed_ips))
  
                      if questionable_ips:
                          # Update list of currently questionable IPs with any
                          # new ones
                          currently_questionable_ips.update(failed_ips)
                          logging.info('Currently questionable IPs: %s' %
                                       ",".join(currently_questionable_ips))
                          # Let the main loop know the full set of questionable
                          # IPs
                          self.q_questionable_ips.put(
                                              list(currently_questionable_ips))
  
                  if interval_count == recheck_failed_interval:
                      # Ever now and then clean out our currently failed IP cache
                      # so that we can recheck them to see if they are still
                      # failed. We also clear out the questionable IPs, so that
                      # they don't forever accumulate.
                      interval_count             = 0
                      currently_failed_ips       = set()
                      currently_questionable_ips = set()
  
                  # Wait until next monitoring interval: We deduct the time we
                  # spent in this loop.
                  end_time = time.time()
                  time.sleep(self.get_monitor_interval() -
                             (end_time - start_time))
                  interval_count += 1
  
              logging.debug("Monitoring loop ended: Global stop")
  
          except StopReceived:
              # Received the stop signal, just exiting the thread function
              return