1195. Fizz Buzz Multithreaded - cocoder39/coco39_LC GitHub Wiki
Option 1: condition
without self.cur > self.n
, it can happen that a thread acquires lock, self.cur == self.n
at the point, but condition_func
is unable to be satisfied so the thread is blocked on wait()
and releases lock. The other thread acquires the lock, increment self.cur
then notifies the first thread. First thread evaluates condition, and condition is not able to be satisfied so it releases lock again. No thread is able to update self.cur
anymore.
from threading import Condition
class FizzBuzz:
def __init__(self, n: int):
self.n = n
self.cur = 1
self.condition = Condition()
# printFizz() outputs "fizz"
def fizz(self, printFizz: 'Callable[[], None]') -> None:
self.exe(lambda num: printFizz(), lambda num: num % 3 == 0 and num % 5 != 0)
# printBuzz() outputs "buzz"
def buzz(self, printBuzz: 'Callable[[], None]') -> None:
self.exe(lambda num: printBuzz(), lambda num: num % 3 != 0 and num % 5 == 0)
# printFizzBuzz() outputs "fizzbuzz"
def fizzbuzz(self, printFizzBuzz: 'Callable[[], None]') -> None:
self.exe(lambda num: printFizzBuzz(), lambda num: num % 3 == 0 and num % 5 == 0)
# printNumber(x) outputs "x", where x is an integer.
def number(self, printNumber: 'Callable[[int], None]') -> None:
self.exe(lambda num: printNumber(num), lambda num: num % 3 != 0 and num % 5 != 0)
def exe(self, print_fun, condition_func):
with self.condition:
while self.cur <= self.n:
self.condition.wait_for(lambda: condition_func(self.cur) or self.cur > self.n)
if self.cur > self.n:
return
else:
print_fun(self.cur)
self.cur += 1
self.condition.notifyAll()
Option 2; barrier
from threading import Barrier
class FizzBuzz:
def __init__(self, n: int):
self.n = n
self.barrier = Barrier(4)
# printFizz() outputs "fizz"
def fizz(self, printFizz: 'Callable[[], None]') -> None:
self.exe(lambda num: printFizz(), lambda num: num % 3 == 0 and num % 5 != 0)
# printBuzz() outputs "buzz"
def buzz(self, printBuzz: 'Callable[[], None]') -> None:
self.exe(lambda num: printBuzz(), lambda num: num % 3 != 0 and num % 5 == 0)
# printFizzBuzz() outputs "fizzbuzz"
def fizzbuzz(self, printFizzBuzz: 'Callable[[], None]') -> None:
self.exe(lambda num: printFizzBuzz(), lambda num: num % 15 == 0)
# printNumber(x) outputs "x", where x is an integer.
def number(self, printNumber: 'Callable[[int], None]') -> None:
self.exe(lambda num: printNumber(num), lambda num: num % 3 != 0 and num % 5 != 0)
def exe(self, print_fun, condition_func):
for num in range(1, self.n+1):
if condition_func(num):
print_fun(num)
self.barrier.wait()
Option 3: semaphore
from threading import Semaphore
class FizzBuzz:
def __init__(self, n: int):
self.n = n
self.fs = Semaphore(0)
self.bs = Semaphore(0)
self.fbs = Semaphore(0)
self.ns = Semaphore(1)
# printFizz() outputs "fizz"
def fizz(self, printFizz: 'Callable[[], None]') -> None:
for num in range(self.n//3 - self.n//15):
self.fs.acquire()
printFizz()
self.ns.release()
# printBuzz() outputs "buzz"
def buzz(self, printBuzz: 'Callable[[], None]') -> None:
for num in range(self.n//5 - self.n//15):
self.bs.acquire()
printBuzz()
self.ns.release()
# printFizzBuzz() outputs "fizzbuzz"
def fizzbuzz(self, printFizzBuzz: 'Callable[[], None]') -> None:
for num in range(self.n // 15):
self.fbs.acquire()
printFizzBuzz()
self.ns.release()
# printNumber(x) outputs "x", where x is an integer.
def number(self, printNumber: 'Callable[[int], None]') -> None:
for num in range(1, self.n+1):
self.ns.acquire()
if num % 15 == 0:
self.fbs.release()
elif num % 3 == 0:
self.fs.release()
elif num % 5 == 0:
self.bs.release()
else:
printNumber(num)
self.ns.release()
Option 4: Lock
from threading import Lock
class FizzBuzz:
def __init__(self, n: int):
self.n = n
self.fs = Lock()
self.bs = Lock()
self.fbs = Lock()
self.ns = Lock()
self.fs.acquire()
self.bs.acquire()
self.fbs.acquire()
# printFizz() outputs "fizz"
def fizz(self, printFizz: 'Callable[[], None]') -> None:
for num in range(self.n//3 - self.n//15):
self.fs.acquire()
printFizz()
self.ns.release()
# printBuzz() outputs "buzz"
def buzz(self, printBuzz: 'Callable[[], None]') -> None:
for num in range(self.n//5 - self.n//15):
self.bs.acquire()
printBuzz()
self.ns.release()
# printFizzBuzz() outputs "fizzbuzz"
def fizzbuzz(self, printFizzBuzz: 'Callable[[], None]') -> None:
for num in range(self.n // 15):
self.fbs.acquire()
printFizzBuzz()
self.ns.release()
# printNumber(x) outputs "x", where x is an integer.
def number(self, printNumber: 'Callable[[int], None]') -> None:
for num in range(1, self.n+1):
self.ns.acquire()
if num % 15 == 0:
self.fbs.release()
elif num % 3 == 0:
self.fs.release()
elif num % 5 == 0:
self.bs.release()
else:
printNumber(num)
self.ns.release()