def acquire_shared(self, timeout = None):
        """
        Attempts to acquire the lock in shared mode within the optional 
        timeout. If the timeout is not specified, waits for the lock
        infinitely. Returns True if the lock has been acquired, False
        otherwise.
        """

        thrCurrent = currentThread()

        self._lock()
        try:

            if self.__log: self._log("acquiring shared")
            if self.__debug:
                assert self._invariant(), "SharedLock invariant failed: %s in %s" % \
                                          (self._debug_dump(), trace_string())

            # this thread already has shared lock, the count is incremented

            if thrCurrent in self.dicUsers: 
                self.dicUsers[thrCurrent] += 1
                if self.__debug:
                    assert self._invariant(), "SharedLock invariant failed: %s in %s" % \
                                              (self._debug_dump(), trace_string())
                if self.__log: self._log("acquired shared")
                return True

            # this thread already has exclusive lock, now it also has shared

            elif thrCurrent is self.thrOwner: 
                if thrCurrent in self.dicUsers:
                    self.dicUsers[thrCurrent] += 1
                else:
                    self.dicUsers[thrCurrent] = 1
                if self.__debug:
                    assert self._invariant(), "SharedLock invariant failed: %s in %s" % \
                                              (self._debug_dump(), trace_string())
                if self.__log: self._log("acquired shared")
                return True

            # a thread acquires shared lock whenever there is no owner
            # nor pending owners (to prevent owners starvation)

            elif not self._has_owner() and not self._has_pending_owners():
                self.dicUsers[thrCurrent] = 1
                if self.__debug:
                    assert self._invariant(), "SharedLock invariant failed: %s in %s" % \
                                              (self._debug_dump(), trace_string())
                if self.__log: self._log("acquired shared")
                return True

            # otherwise the thread registers itself as a pending user

            else:

                evtEvent = self._pick_event()
                self.lstUsers.append((thrCurrent, evtEvent, 1))

            if self.__debug:
                assert self._invariant(), "SharedLock invariant failed: %s in %s" % \
                                          (self._debug_dump(), trace_string())
            if self.__log: self._log("waiting for shared")

        finally:
            self._unlock()

        return self._acquire_event(evtEvent, timeout) # the thread waits for a lock release

        Attempts to acquire the lock in shared mode within the optional 
        timeout. If the timeout is not specified, waits for the lock
        infinitely. Returns True if the lock has been acquired, False
        otherwise.
        
recipes/Python/465156_Shared_lock_akreaderwriter_lock_timeouts_FIFO/recipe-465156.py