Last active
April 28, 2020 14:47
-
-
Save stanleyvarga/da3d4d4281ef3c94698dac4f8fe5b73c to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python | |
import time | |
import logging | |
import threading | |
logging.basicConfig(format="[%(asctime)s]: %(message)s", level=logging.INFO, datefmt="%H:%M:%S") | |
class STATE: | |
def __init__(self): | |
self.condition = None | |
self.simulationRun = 1 | |
self.noPaintersToWaitFor = 0 | |
self.paintersMetUntilBreak = 0 | |
self.painterBreakWhenBucketCountIs = 4 | |
self.paintersOnBreak = [] | |
self.totalBuckets = 0 | |
SIMULATION_TIME = 10 | |
NO_PAINTERS = 5 | |
NO_PAINTERS_TO_WAIT_FOR = 2 | |
PAINTERS_BREAK_WHEN_BUCKET_COUNT_IS = 4 | |
PAINTER_TIMING_BREAK = 0.5 | |
PAINTER_TIMING_PAINT = 1 | |
PAINTER_TIMING_BUCKET_GET = 0.5 | |
# maliar pocka maximalne PAINTER_TIMING_WAIT_MAX sekund, | |
# potom sa unudi a da sa znova do prace | |
PAINTER_TIMING_WAIT_MAX = 1 | |
class Painter: | |
def __init__(self, state, name): | |
self.buckets = 0 | |
self.name = name | |
self.state = state | |
def doPainting(self): | |
logging.info("%s Painting...", self.name) | |
time.sleep(PAINTER_TIMING_PAINT) | |
def goGetNewBucket(self): | |
logging.info("%s Taking Bucket...", self.name) | |
time.sleep(PAINTER_TIMING_BUCKET_GET) | |
self.buckets += 1 | |
state.totalBuckets += 1 | |
# Python nam velmi rad pomoze s releasom mutexu, aby sme nan nezabudli | |
# namiesto mutex/cond.acquire() a potom mutex/cond.release() | |
# obalime logiku do `with mutex/cond:` -> acquire a release prekladac doplni za nas | |
with state.condition: | |
if self.buckets % state.painterBreakWhenBucketCountIs == 0: | |
# to co robila bariera predtym robime my rucne, | |
# teda zistujeme kolko vlakien ma este cakat | |
# + 1 pretoze napr. jeden maliar caka na dalsich dvoch = 3 dokopy | |
if state.paintersMetUntilBreak != state.noPaintersToWaitFor + 1: | |
logging.info("%s waiting for %s more painters", self.name, state.noPaintersToWaitFor - state.paintersMetUntilBreak) | |
# inkrementujeme counter aby sme vedeli kedy uz necakat | |
state.paintersMetUntilBreak += 1 | |
# vlakno caka, kym nie je splnena podmienka resp. counter | |
# alebo vyprsi cas | |
state.condition.wait(PAINTER_TIMING_WAIT_MAX) | |
# Teraz notify_all povie vsetkym vlaknam, ze toto vlakno je uvolnene | |
# a teda uz necaka, pokracuje kod nizsie | |
state.condition.notify_all() | |
# Resetneme counter bariery aby mohla zacat od znova | |
state.paintersMetUntilBreak = 0 | |
logging.info("%s Having a break", self.name) | |
time.sleep(PAINTER_TIMING_BREAK) | |
def run(self): | |
while self.state.simulationRun: | |
self.goGetNewBucket() | |
self.doPainting() | |
if __name__ == "__main__": | |
logging.info("Start Main Thread") | |
state = STATE() | |
state.noPaintersToWaitFor = NO_PAINTERS_TO_WAIT_FOR | |
# threading.Rlock je lepsi ako threaing.Lock v tom, | |
# ze pokial zabudneme releasnut mutex, RLock nesposobi deadlock | |
state.condition = threading.Condition(threading.RLock()) | |
painters = [] | |
threads = [] | |
for i in range(NO_PAINTERS): | |
painters.append( Painter( | |
state, | |
"Painter-{}".format(i) | |
) | |
) | |
for i in range(NO_PAINTERS): | |
threads.append( threading.Thread( | |
target=painters[i].run, | |
args=() | |
) | |
) | |
for t in threads: | |
t.start() | |
time.sleep(SIMULATION_TIME) | |
state.simulationRun = 0 | |
for t in threads: | |
t.join() | |
logging.info("Total Buckets: %s", state.totalBuckets) | |
for painter in painters: | |
logging.info("%s buckets: %s", painter.name, painter.buckets) | |
logging.info("Exit Main Thread") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment