class Synchronizer(object):
    def __init__(self):
        self.__objects = []
        self.__remaining = []
        self.__remainderSyncs = set()
        self.__remaindersInvoked = False
        self.__blocked = True

    def join(self, obj, remainder = False):
        assert isinstance(obj, ISynchronizable)
        self.__objects.append(obj)
        self.__remaining.append(obj)
        if remainder:
            self.__remainderSyncs.add(obj)

    def leave(self, obj):
        self.__objects.remove(obj)
        if obj in self.__remaining:
            self.__remaining.remove(obj)
        if obj in self.__remainderSyncs:
            self.__remainderSyncs.remove(obj)
        self.__maybeProceed()

    def start(self):
        self.__blocked = False
        self.__maybeProceed()

    def reached(self, obj):
        try:
            self.__remaining.remove(obj)
        except ValueError:
            raise RuntimeError, "'%s' already reached barrier" % `obj`
        self.__maybeProceed()

    def __maybeProceed(self):
        if self.__blocked:
            return
        if len(self.__remaining):
            if not self.__remaindersInvoked:
                # Are all remaining syncs remainder syncs?
                for obj in self.__remaining:
                    if obj not in self.__remainderSyncs:
                        break
                else:
                    # Invoke remainder syncs
                    self.__remaindersInvoked = True
                    for obj in self.__remaining:
                        obj.onSyncRemainder()
        else:
            # All have reached the barrier, proceed
            for obj in self.__objects:
                obj.onSyncProceed()
                self.__remaining.append(obj)
            self.__remaindersInvoked = False

    def reset(self):
        # Put all objects in the remaining set
        self.__remaining = self.__objects[:]
        self.__remaindersInvoked = False

    def dump(self):
        print "<Synchronizer"
        print "  remaining:"
        for obj in self.__objects:
            if obj in self.__remaining:
                print "    %s" % `obj`,
                if obj in self.__remainderSyncs:
                    print "(r)",
                print
        print "  passed:"
        for obj in self.__objects:
            if obj not in self.__remaining:
                print "    %s" % `obj`,
                if obj in self.__remainderSyncs:
                    print "(r)",
                print
        print "  >"

class ISynchronizable(object):
    def onSyncProceed(self):
        pass

    def onSyncRemainder(self):
        pass
