<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def _send_message_with_response(self, operation, read_preference=None, exhaust=False, address=None):
 """Send a message to MongoDB and return a Response. :Parameters: - `operation`: a _Query or _GetMore object. - `read_preference` (optional):
 A ReadPreference. - `exhaust` (optional):
 If True, the socket used stays checked out. It is returned along with its Pool in the Response. - `address` (optional):
 Optional address when sending a message to a specific server, used for getMore. """

        with self.__lock:
            # If needed, restart kill-cursors thread after a fork.
            self._kill_cursors_executor.open()

        topology = self._get_topology()
        if address:
            server = topology.select_server_by_address(address)
            if not server:
                raise AutoReconnect('server %s:%d no longer available'
                                    % address)
        else:
            selector = read_preference or writable_server_selector
            server = topology.select_server(selector)

        # A _Query's slaveOk bit is already set for queries with non-primary
        # read preference. If this is a direct connection to a mongod, override
        # and *always* set the slaveOk bit. See bullet point 2 in
        # server-selection.rst#topology-type-single.
        set_slave_ok = (
            topology.description.topology_type == TOPOLOGY_TYPE.Single
            and server.description.server_type != SERVER_TYPE.Mongos)

        return self._reset_on_error(
            server,
            server.send_message_with_response,
            operation,
            set_slave_ok,
            self.__all_credentials,
            self._event_listeners,
            exhaust)