讀者寫者問題是作業系統領域一個重要的問題。分為讀者優先與寫者優先兩種。
通過加鎖的方式,實作對臨界資源的通路控制。
下面以寫者優先為例子,以Python為實作方式實作讀者寫者問題。
輔助類:随機一個票号
class CreateRandomPage:
# get a random list which use num that
# between self.begin and self.end
# and length that is self.needcount
def __createrandompage(self):
import random
tempInt = random.randint(self.begin, self.end)
if self.count < self.needcount:
if tempInt not in self.resultlist:
self.resultlist.append(tempInt) # 将産生的随機數追加到清單中
self.count += 1
return self.__createrandompage() # 在此用遞歸的思想
return self.resultlist
# list2str
def __getRandomPageNumber(self):
self.resultlist = []
self.count = 0
return ''.join(map(str,self.__createrandompage()))
# num為随機數組的長度 随機出一個10位的包含0-9的數字
def getRandomPageList(self,num):
self.begin = 0
self.end = 9
self.needcount = 10
ans = []
for i in range(num):
str = self.__getRandomPageNumber()
ans.append(str)
ans = list(set(ans))
for j in range(len(ans),num):
str = self.__getRandomPageNumber()
if str not in ans:
ans.append(str)
else:
j-=1
ans.sort()
return ans
讀者寫者問題關鍵代碼:
import time
import random
import Practice.Practice3.RandomIndex as Ran
import threading
class Ticket(object):
# This is a writer-reader problem
# use writer priority
# it means that if a writer come and want to write
# after the last reader read the data
# the writer can cut in line before all readers that not in critical resource
# also, if a writer read now
# a reader can read when all writers have writed
def __init__(self,num):
self.accessReaderCnt = threading.Lock()
self.accessWriterCnt = threading.Lock()
self.writeLock = threading.Lock()
self.readerLock = threading.Lock()
self.outerLock = threading.Lock()
self.readerCnt = 0
self.writerCnt = 0
ran = Ran.CreateRandomPage()
self.tickets = ran.getRandomPageList(num)
def __write(self,tname):
sum = len(self.tickets)
if sum<=0:
print("{}:沒票買了,俺先溜了!".format(tname))
return str(sum)
ticket = self.tickets.pop(random.randint(0,sum-1))
print("{}:購票成功!票号為{}!".format(tname, ticket))
return ticket
def __read(self,tname):
sum = len(self.tickets)
if sum<=0:
print("{}:沒票買了,俺先溜了!".format(tname))
return str(sum)
print("{} 目前還有{}張票,我馬上就來買!".format(tname, sum))
return str(sum)
def Query(self,tname):
# let reader in queue
# the outerLock is the most IMPORTANT lock
# think this situation
# if there are many readers,no writer
# at some time, a writer come
# if the outerLock exist,there is only one reader in outerLock
# reader unlock readerLock faster than outerLock
# you can look the writer, it can access accessWriterCnt (Look at line 91),
# and wait to lock readerLock(read wait at readerLock)
# because the accessReaderCnt unlock faster than readerLock
# so if a writer come, writer can fastly get readerLock, and lock it
# it means that writer can access critical resource faster than many readers
with self.outerLock:#996
# look if writer lock readerLock
# if readerLock is none,reader begin to read
with self.readerLock:
# change reader num, lock it
with self.accessReaderCnt:#1
self.readerCnt+=1
if self.readerCnt==1:
# if some reads reading now
# writer must wait
# so lock writeLock
self.writeLock.acquire()
# read operation
ans = self.__read(tname)
# change reader num, lock it
with self.accessReaderCnt:
self.readerCnt-=1
# there is no reader reading now
# so unlock writeLock
if self.readerCnt==0:
self.writeLock.release()
time.sleep(random.randint(1,100)/1000)
return ans
# Sell tricket
def Sell(self,tname):
# accessWriterCnt control writerCnt number change
with self.accessWriterCnt:
self.writerCnt+=1
# has writers, lock readerLock,
# readers which not in readerLock will can't get readerLock
if self.writerCnt==1:
self.readerLock.acquire()
# write want to write, lock it
with self.writeLock:
# write operation
ans = self.__write(tname)
# want to change writerCnt, lock it
with self.accessWriterCnt:
self.writerCnt-=1
# writer's number is zero
# stand for no writers now
# so readers can read now, unlock readerLock
if self.writerCnt==0:
self.readerLock.release()
time.sleep(random.randint(1,100)/1000)
return ans
輔助類,顧客:
import random
import time
import threading
import Practice.Practice3.Ticketer as Ticket
class Customers(object):
def __init__(self,num):
self.num=num
# 線程任務 tname線程名 ticketer售票處
def __threadTask(self,tname,ticketer):
while True:
# 随機一個數 每個線程都能去買票或者問詢 25%幾率買,75%幾率問
opt = random.random()
if opt>0.75:
result = ticketer.Sell(tname)
if result == "0":
break
else:
result = ticketer.Query(tname)
if result == "0":
break
time.sleep(random.randint(1000,1500)/1000)
# 線程運作 num運作數目 ticketer售票處
def Run(self,ticketer):
tname=["客戶"]*self.num
threadList = []
for i in range(self.num):
tname[i]+=str((i+1))
new_thread = threading.Thread(target=self.__threadTask, args=(tname[i],ticketer,))
threadList.append(new_thread)
numList = [a for a in range(self.num)]
random.shuffle(numList)
for i in numList:
threadList[i].start()
if __name__ == '__main__':
ticketer = Ticket.Ticket(int(input("票站票數:")))
threads = Customers(int(input("顧客人數:")))
threads.Run(ticketer)