读者写者问题是操作系统领域一个重要的问题。分为读者优先与写者优先两种。
通过加锁的方式,实现对临界资源的访问控制。
下面以写者优先为例子,以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)