resource request racing problem
Created by: chof2
Hello,
I have a racing issue in resource assignment that I think is a serious problem. To demonstrate the problem please consider the following definitions:
#!python
def a(env,res):
print('Enter a at ' + str(env.now))
with res.request(priority=0) as req:
yield req
print('a got res at ' + str(env.now))
try:
yield env.timeout(10)
except simpy.Interrupt as interrupt:
print('a preemted at' + str(env.now) + ', start time: ' + str(interrupt.cause.usage_since))
print('leaving a at ' + str(env.now))
def a2(env,res):
print('Enter a2 at ' + str(env.now))
with res.request(priority=0) as req:
try:
yield req
print('a2 got res at ' + str(env.now))
yield env.timeout(10)
except simpy.Interrupt as interrupt:
print('a2 preemted at' + str(env.now) + 'usage since: ' + str(interrupt.cause.usage_since))
print('leaving a2 at ' + str(env.now))
def b(env,res):
print('Enter b at ' + str(env.now))
with res.request(priority=-1) as req:
yield req
print('b got res at ' + str(env.now))
try:
yield env.timeout(3)
except simpy.Interrupt as interrupt:
print('b preemted at' + str(env.now))
print('leaving b at ' + str(env.now))
def p1():
yield env.timeout(1)
yield env.process(a2(env,res))
def p1a():
yield env.timeout(1)
yield env.process(a(env,res))
yield env.timeout(4)
yield env.process(a(env,res))
def p2():
yield env.timeout(1)
yield env.process(b(env,res))
Now, if you have the following run:
#!python
env = simpy.Environment()
res = simpy.PreemptiveResource(env,capacity=1)
env.process(p1a())
env.process(p2())
env.run(100)
both a and b kind of race to get the resource and an interrupt kills the program while the logical things to happen is that b gets it first and then a should wait as it is of less priority. After all they both arrive at the same time as far as the simulation is considered.
Next, note that if I switch the order of process creation of p2 and p1a, the correct logical order is carried. That is if you use:
#!python
env = simpy.Environment()
res = simpy.PreemptiveResource(env,capacity=1)
env.process(p2())
env.process(p1a())
env.run(100)
Then all is fine. What I think should have been is that both order of process assignments should provide the very same results while in current situation one is very problematic (the interrupt terminates the program completely as it is not excepted.
Bdw, If one except the interrupt as in p1, that is use the following code:
#!python
env = simpy.Environment()
res = simpy.PreemptiveResource(env,capacity=1)
env.process(p1())
env.process(p2())
env.run(100)
then the program is not termined with error BUT, the logical execution of events is WRONG. a2 should not actually be preempted as it came together with b and therefore the correct order is that b takes the resources and a2 waits, while here 2a is preempted, not waiting for its turn. Well,.. that is because we used the yield resources within the try...so the program does not terminates but logically this is not what one is expected.
Things can get more complicated, as there are times where two requests come at the same time but the correct order is magically happen.
Add the following definition please:
#!python
def p3():
yield env.timeout(15)
yield env.process(b(env,res))
Now, if you run:
#!python
env = simpy.Environment()
res = simpy.PreemptiveResource(env,capacity=1)
env.process(p1a())
env.process(p3())
env.run(100)
Then both b and a request at 15 but the correct execution with not interrupts happen. That is, b gets the resources and a waits as they both request at the same time but b is with higher priority.
To make things more complicated, please consider the additional definition:
#!python
def p4():
yield env.timeout(15)
yield env.process(b(env,res))
yield env.timeout(5)
yield env.process(b(env,res))
and take a look what happens when you run the following:
#!python
env = simpy.Environment()
res = simpy.PreemptiveResource(env,capacity=1)
env.process(p1a())
env.process(p4())
env.run(100)
Here you have another serious problem. See please that the second time a request the resources is at time 15 BUT, a gets it only at time 18. Nevertheless, when a is preempted, we see that it claims to work since time 15 (when using the interrupt.cause.usage_since).