Python 3 | 6 Approaches | Explanation
Before you proceed\n- Intuition: Make sure the executing order using Lock or similar mechanism.\n- Technically 8 approaches since the first two can be rewrote u
## Before you proceed\n- **Intuition**: Make sure the executing order using `Lock` or similar mechanism.\n- Technically 8 approaches since the first two can be rewrote using `Semaphore`. \n\n## Approach \\#1. Lock/Semaphore only\n```python\nfrom threading import Lock\nclass FooBar:\n    def __init__(self, n):\n        self.n = n\n        self.l1 = Lock() # Semaphore(1)\n        self.l2 = Lock() # Semaphore(1)\n        self.l2.acquire()\n\n    def foo(self, printFoo: \'Callable[[], None]\') -> None:\n        for i in range(self.n):\n            self.l1.acquire()\n            printFoo()\n            self.l2.release()\n\n    def bar(self, printBar: \'Callable[[], None]\') -> None:\n        for i in range(self.n):\n            self.l2.acquire()\n            printBar()\n            self.l1.release()\n```\n\n## Approach \\#2. Lock/Semaphore + Barrier\n```python\nfrom threading import Barrier, Lock #, Semaphore\nclass FooBar:\n    def __init__(self, n):\n        self.n = n\n        self.b = Barrier(2)\n        self.l = Lock() # Semaphore(1)\n        self.l.acquire()\n\n    def foo(self, printFoo: \'Callable[[], None]\') -> None:\n        for i in range(self.n):\n            printFoo()\n            self.l.release()\n            self.b.wait()\n\n    def bar(self, printBar: \'Callable[[], None]\') -> None:\n        for i in range(self.n):\n            with self.l:\n                printBar()\n            self.b.wait()\n            self.l.acquire()\n```\n## Approach \\#3. Condition only\n```python\nfrom threading import Condition\nclass FooBar:\n    def __init__(self, n):\n        self.n = n\n        self.c1 = Condition()\n        self.f = True\n\n    def foo(self, printFoo: \'Callable[[], None]\') -> None:\n        for i in range(self.n):\n            with self.c1:\n                self.c1.wait_for(lambda: self.f)\n                printFoo()\n                self.f = False\n                self.c1.notify(1)\n\n    def bar(self, printBar: \'Callable[[], None]\') -> None:\n        for i in range(self.n):\n            with self.c1:\n                self.c1.wait_for(lambda: not self.f)\n                printBar()\n                self.f = True\n                self.c1.notify(1)\n```\n\n## Approach \\#4. Condition + Barrier\n```python\nfrom threading import Condition, Barrier\nclass FooBar: \n    def __init__(self, n):\n        self.n = n\n        self.br = Barrier(2)\n        self.c = Condition()\n        self.f = False\n\n    def foo(self, printFoo: \'Callable[[], None]\') -> None:\n        for i in range(self.n):\n            with self.c:\n                printFoo()\n                self.f = True\n                self.c.notify_all()\n            self.br.wait()\n\n    def bar(self, printBar: \'Callable[[], None]\') -> None:\n        for i in range(self.n):\n            with self.c:\n                self.c.wait_for(lambda: self.f)\n                printBar()            \n                self.f = False\n            self.br.wait()\n```\n\n\n## Approach \\#5. Event only\n```python\nfrom threading import Event\nclass FooBar:\n    def __init__(self, n):\n        self.n = n\n        self.e = Event()\n        self.e1 = Event()\n\n    def foo(self, printFoo: \'Callable[[], None]\') -> None:\n        for i in range(self.n):\n            printFoo()\n            self.e.set() \n            self.e1.wait()\n            self.e1.clear()\n\n    def bar(self, printBar: \'Callable[[], None]\') -> None:\n        for i in range(self.n):\n            self.e.wait()\n            printBar()\n            self.e1.set()\n            self.e.clear() \n```\n\n\n## Approach \\#6. Event + Barrier\n```python\nfrom threading import Event, Barrier\nclass FooBar:\n    def __init__(self, n):\n        self.n = n\n        self.br = Barrier(2)\n        self.e = Event()\n\n    def foo(self, printFoo: \'Callable[[], None]\') -> None:\n        for i in range(self.n):\n            printFoo()\n            self.e.set()\n            self.br.wait()\n\n    def bar(self, printBar: \'Callable[[], None]\') -> None:\n        for i in range(self.n):\n            self.e.wait()\n            printBar()\n            self.e.clear()\n            self.br.wait()\n```
['Concurrency', 'Python3']