You have the four functions:
printFizzthat prints the word
"fizz"to the console,
printBuzzthat prints the word
"buzz"to the console,
printFizzBuzzthat prints the word
"fizzbuzz"to the console, and
printNumberthat prints a given integer to the console.
You are given an instance of the class FizzBuzz that has four functions: fizz, buzz, fizzbuzz and number. The same instance of FizzBuzz will be passed to four different threads:
Thread A: calls
fizz()that should output the word
Thread B: calls
buzz()that should output the word
Thread C: calls
fizzbuzz()that should output the word
Thread D: calls
number()that should only output the integers.
Modify the given class to output the series [1, 2, "fizz", 4, "buzz", ...] where the ith token (1-indexed) of the series is:
"fizzbuzz" if i is divisible by 3 and 5,
"fizz" if i is divisible by 3 and not 5,
"buzz" if i is divisible by 5 and not 3, or
i if i is not divisible by 3 or 5.
Implement the FizzBuzz class:
FizzBuzz(int n) Initializes the object with the number n that represents the length of the sequence that should be printed.
void fizz(printFizz) Calls printFizz to output "fizz".
void buzz(printBuzz) Calls printBuzz to output "buzz".
void fizzbuzz(printFizzBuzz) Calls printFizzBuzz to output "fizzbuzz".
void number(printNumber) Calls printnumber to output the numbers.
Input: n = 15 Output: [1,2,"fizz",4,"buzz","fizz",7,8,"fizz","buzz",11,"fizz",13,14,"fizzbuzz"]
Input: n = 5 Output: [1,2,"fizz",4,"buzz"]
n, n times.
check for every value of n ranging from 1 to n, if it mets the condition
Print out the right word.
for i in range(1,self.n+1): if "condition is true": "printWord()"
Let's understand this First!
Let's assume the order of thread execution is as follows
Thread C and
Thread D. The first step would be to write the logic of the code in the each of methods that run our functions to suit what each method is suppose to print out.
We loop through n and check if each value of n ranging from 1 to n mets the condition in the method. Unfortunately, Knowing the order of the thread and that Thread A runs first which automatically calls buzz method.
This would leave us in a complex situtation because Thread A would have to run n number of times before Thread B picks up. Sadly this is not we want to achieve. We want a situation where Thread A pauses after the first iteration permitting Thread B to run and then, Thread C picks up after Thread B's first iteration and same for Thread D. In other words, I want to keep all threads in sync.
To achieve this, we can use a threading object called
Think of barrier as a delay that interupts a thread from continuing it's operation giving room to the next thread to carry out it's function and any other threads before the initial thread picks up from where it's last stop.
from threading import Barrier class FizzBuzz: def __init__(self, n: int): self.n = n self.block = Barrier(4) # printFizz() outputs "fizz" def fizz(self, printFizz: 'Callable[, None]') -> None: for i in range(1,self.n+1): if i%5!=0 and i%3==0: printFizz() self.block.wait() # printBuzz() outputs "buzz" def buzz(self, printBuzz: 'Callable[, None]') -> None: for i in range(1,self.n+1): if i%3!=0 and i %5 ==0: printBuzz() self.block.wait() # printFizzBuzz() outputs "fizzbuzz" def fizzbuzz(self, printFizzBuzz: 'Callable[, None]') -> None: for i in range(1,self.n+1): if i%5==0 and i%3==0: printFizzBuzz() self.block.wait() # printNumber(x) outputs "x", where x is an integer. def number(self, printNumber: 'Callable[[int], None]') -> None: for i in range(1,self.n+1): if (i % 3) !=0 and (i%5) !=0: printNumber(i) self.block.wait()
Understanding the Code
- Initialize barrier to 4, making it understand that 4 threads would be in sync. This would mean all 4 thread must hit the wait
self.block = Barrier(4)
Starting our Program, Thread A calls Buzz method, The loop begins from 1 then our
ifstatement is skipped because the condition is false which leads to the next line of code
self.bar.wait(). This prevents
buzzmethod from running next iteration and giving control to next thread which is
# printBuzz() outputs "buzz" def buzz(self, printBuzz: 'Callable[, None]') -> None: for i in range(1,self.n+1): if i%3!=0 and i %5 ==0: printBuzz() self.block.wait()
The advantage of this approach is that all threads would remain blocked when they call
wait()until the barrier reaches the specified number of threads waiting to be blocked before they get unblocked.