def add_task(self, target, args=(), kwargs=None, priority=None):
        """
        Args:
            target: A callable object to be invoked
            args: Arguments sent to the callable object upon invocation
            kwargs: Keyword arguments sent to the callable object upon invocation
            priority: Determines where to put the callable object in the list of tasks, Can be any type of object that
                is comparable using comparison operators (lower = higher priority)
        Returns:
            If a new thread was started returns the threading object otherwise returns None
        Raises:
            RuntimeError: If trying to add new task after closing object
        """

        if self._stop:
            raise RuntimeError("Can't add new task, the MaxThreads object is in closing/closed state")

        new_thread = None

        if (self.threads_active() < self._max_threads or not self._limit) \
            and (self._threads_waiting == 0 and self._queue.qsize() > 0):
            # The number of active threads is less than maximum number of threads
            # OR there is no limit on the maximum number of threads
            # AND there are no threads in waiting state
            # i.e. start a new thread
            new_thread = self._start_loop_thread()

        self._queue.put(
            SetPrio(target=target,
                    args=args,
                    kwargs=kwargs or {},
                    priority=priority or 0)
        )

        return new_thread