1115. Print FooBar Alternately - cocoder39/coco39_LC GitHub Wiki

1115. Print FooBar Alternately

Option 1: condition

from threading import Condition

class FooBar:
    def __init__(self, n):
        self.n = n
        self.condition = Condition()
        self.count = 0
        
    def foo(self, printFoo: 'Callable[[], None]') -> None:
        for i in range(self.n):
            with self.condition:
                self.condition.wait_for(lambda: 2*i == self.count)
                # printFoo() outputs "foo". Do not change or remove this line.
                printFoo()
                self.count += 1
                self.condition.notifyAll()

    def bar(self, printBar: 'Callable[[], None]') -> None:
        for i in range(self.n):
            with self.condition:
                self.condition.wait_for(lambda: 2*i+1 == self.count)
                # printBar() outputs "bar". Do not change or remove this line.
                printBar()
                self.count += 1
                self.condition.notifyAll()

Option 2: event

from threading import Event

class FooBar:
    def __init__(self, n):
        self.n = n
        self.foo_event = Event()
        self.bar_event = Event()
        self.foo_event.set()
        
    def foo(self, printFoo: 'Callable[[], None]') -> None:
        for i in range(self.n):
            self.foo_event.wait()
            self.foo_event.clear()
            # printFoo() outputs "foo". Do not change or remove this line.
            printFoo()
            self.bar_event.set()

    def bar(self, printBar: 'Callable[[], None]') -> None:
        for i in range(self.n):
            self.bar_event.wait()
            self.bar_event.clear()
            # printBar() outputs "bar". Do not change or remove this line.
            printBar()
            self.foo_event.set()

Option 3: semaphore

from threading import Semaphore

class FooBar:
    def __init__(self, n):
        self.n = n
        self.foo_event = Semaphore(1)
        self.bar_event = Semaphore(0)
        
    def foo(self, printFoo: 'Callable[[], None]') -> None:
        for i in range(self.n):
            self.foo_event.acquire()
            # printFoo() outputs "foo". Do not change or remove this line.
            printFoo()
            self.bar_event.release()

    def bar(self, printBar: 'Callable[[], None]') -> None:
        for i in range(self.n):
            self.bar_event.acquire()
            # printBar() outputs "bar". Do not change or remove this line.
            printBar()
            self.foo_event.release()

Option 4: lock

from threading import Lock

class FooBar:
    def __init__(self, n):
        self.n = n
        self.foo_event = Lock()
        self.bar_event = Lock()
        self.bar_event.acquire()
        
    def foo(self, printFoo: 'Callable[[], None]') -> None:
        for i in range(self.n):
            self.foo_event.acquire()
            # printFoo() outputs "foo". Do not change or remove this line.
            printFoo()
            self.bar_event.release()

    def bar(self, printBar: 'Callable[[], None]') -> None:
        for i in range(self.n):
            self.bar_event.acquire()
            # printBar() outputs "bar". Do not change or remove this line.
            printBar()
            self.foo_event.release()

Option 5: barrier

This solution can pass OJ but doesn't guarantee order between foo and bar in theory

EG. pint foo -> foo calls wait -> bar calls wait -> print foo -> print bar

from threading import Barrier

class FooBar:
    def __init__(self, n):
        self.n = n
        self.barrier = Barrier(2)
        
    def foo(self, printFoo: 'Callable[[], None]') -> None:
        for i in range(self.n):
            # printFoo() outputs "foo". Do not change or remove this line.
            printFoo()
            self.barrier.wait()

    def bar(self, printBar: 'Callable[[], None]') -> None:
        for i in range(self.n):
            self.barrier.wait()
            # printBar() outputs "bar". Do not change or remove this line.
            printBar()

Option 6: barrier

This solution can pass OJ but doesn't guarantee order between foo and bar in theory

print foo -> foo calls bar_wait -> bar calls foo wait -> foo calls foo wait -> print foo

from threading import Barrier

class FooBar:
    def __init__(self, n):
        self.n = n
        self.foo_barrier = Barrier(2)
        self.bar_barrier = Barrier(2)
        
    def foo(self, printFoo: 'Callable[[], None]') -> None:
        for i in range(self.n):
            self.foo_barrier.wait()
            # printFoo() outputs "foo". Do not change or remove this line.
            printFoo()
            self.bar_barrier.wait()

    def bar(self, printBar: 'Callable[[], None]') -> None:
        for i in range(self.n):
            self.foo_barrier.wait()
            self.bar_barrier.wait()
            # printBar() outputs "bar". Do not change or remove this line.
            printBar()