Classic Reader Writer Problem
code
import random, simpy
INTERVAL = 3 #the maximum interval of adjacent two operations is 3
MAXTIME = 5 #the maximum execution time of a single operation is 5
datablocks = [] #the list of datablocks. Assume in this project there are 100 datablocks
processQueue = [] #the process waiting queue, set max size 4
req = []
for i in range(50):
req.append(None)
class DataBlock(object): #DataBlock object
def __init__(self, lock, id, readersNum):
self.lock = lock
self.id = id
self.readersNum = readersNum
class Operation(object):
def __init__(self,env,capacity,maxtime):
self.maxtime = maxtime
self.env = env
def read(self, env, name, datablock):
global req
datablock.readersNum = datablock.readersNum + 1
if datablock.readersNum == 1:
req[datablock.id] = datablock.lock.request()
yield req[datablock.id]
print("%s is reading datablock No.%s at %s" %(name,datablock.id,env.now))
operateTime = random.randint(1,MAXTIME)
yield env.timeout(operateTime)
print("%s has finished reading datablock No.%s at %s" %(name,datablock.id,env.now))
datablock.readersNum = datablock.readersNum -1
if datablock.readersNum == 0:
datablock.lock.release(req[datablock.id])
processQueue.remove(name)
def write(self, env, name, datablock):
global req
with datablock.lock.request() as r:
yield r
print("%s is writing datablock No.%s at %s" %(name,datablock.id,env.now))
operateTime = random.randint(1,MAXTIME)
yield env.timeout(operateTime)
print("%s has finished writing datablock No.%s at %s" %(name,datablock.id,env.now))
processQueue.remove(name)
def setup(env, capacity, maxtime, interval,datablocks):
operation = Operation(env,capacity, maxtime)
i = 0
while True:
yield env.timeout(random.randint(0,interval)) #stop for next operation
blockNum = random.randint(0,49) #generate block number randomly
mode = "";
if random.random()<0.25: #according possibility to specify the mode
mode = "W"
else:
mode = "R"
if len(processQueue) == 4: #if the queue is full, wait
yield env.timeout(maxtime*3)
processQueue.append('Operation %d' %i) #push current operate into the queue
db = datablocks[blockNum]
if mode == "R":
env.process(operation.read(env,'Operation %d' % i,db))
else:
env.process(operation.write(env,'Operation %d' % i,db))
i = i+1
#initialize datablock objects
env = simpy.Environment()
for i in range(50):
datablocks.append(DataBlock(simpy.Resource(env, capacity=1),i,0))
env.process(setup(env, 5, MAXTIME, INTERVAL,datablocks))
env.run(until=1000)