讀者寫者問題(寫者優先)的Python實現,以售票爲例

讀者寫者問題是操作系統領域一個重要的問題。分爲讀者優先與寫者優先兩種。

通過加鎖的方式,實現對臨界資源的訪問控制。

下面以寫者優先爲例子,以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)

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章