两个吃奶一个添下面视频_人妻第一页香蕉网_欧美xxxx少妇_妺妺窝人体色www婷婷

不知道大家有沒有在生活中思考或者見別人說過這個(gè)問題,在銀行自助取款機(jī)取錢的時(shí)候,如果同時(shí)按下取一百元和手機(jī)微信支付一百元(假定銀行卡中只有一百元),那樣會(huì)不會(huì)既支付成功又能取出錢呢,答案當(dāng)然是不可能,這就涉及到在多線程的環(huán)境下訪問同一資源的問題,這樣會(huì)引發(fā)線程不安全的可能,下面我們來學(xué)習(xí)一下問題的根源和解決方式。

1. 臨界資源問題

首先我們來了解一下什么是臨界資源,多道程序系統(tǒng)中存在許多進(jìn)程,它們共享各種資源,然而有很多資源一次只能供一個(gè)進(jìn)程使用。一次僅允許一個(gè)進(jìn)程使用的資源稱為臨界資源。許多物理設(shè)備都屬于臨界資源,如輸入機(jī)、打印機(jī)、磁帶機(jī)等。

還有一個(gè)名詞叫臨界區(qū),每個(gè)進(jìn)程中訪問臨界資源的那段代碼稱為臨界區(qū)。顯然,若能保證諸進(jìn)程互斥地進(jìn)入自己的臨界區(qū),便可實(shí)現(xiàn)諸進(jìn)程對(duì)臨界資源的互斥訪問。

我們通過下面的例子來了解一下臨界資源的共用:

import time
import threading
class Apple:
    def __init__(self):
        self.apple_number = 6 #定義6個(gè)蘋果,每個(gè)蘋果有一個(gè)標(biāo)號(hào)
    def get_apple_number(self):
        return self.apple_number
    def sell_apple(self):
        time.sleep(2)#當(dāng)前線程休眠,會(huì)阻塞當(dāng)前的線程,這個(gè)時(shí)間提供給用戶付款,完成付款后執(zhí)行售出操作
        print('第%d個(gè)蘋果已賣'%self.apple_number)
        self.apple_number -= 1
apple = Apple()
def thread_one():
    global apple
    while True:
        query_apple_number = ap.get_apple_number()#查詢是否還有蘋果
        if query_apple_number > 0:#蘋果數(shù)量大于0就執(zhí)行一次出售操作
            ap.sell_apple()
        else:
            break
def thread_two():
    global apple
    while True:
        query_apple_number = ap.get_apple_number()
        if query_apple_number > 0:
            ap.sell_apple()
        else:
            break
if __name__ == '__main__':
    apple_one = threading.Thread(target=thread_one())
    apple_one.start()
    apple_one.join()
    apple_two = threading.Thread(target=thread_two())
    apple_two.start()

輸出結(jié)果為:

第6個(gè)蘋果已賣
第5個(gè)蘋果已賣
第4個(gè)蘋果已賣
第3個(gè)蘋果已賣
第2個(gè)蘋果已賣
第1個(gè)蘋果已賣

我們前面定義了一個(gè)類,類中存在著查詢蘋果和售出蘋果的方法,然后調(diào)用這個(gè)類來創(chuàng)建一個(gè)對(duì)象,然后創(chuàng)建2個(gè)線程體來執(zhí)行買蘋果操作,最后在主程序中創(chuàng)建2個(gè)線程去執(zhí)行指令,通過輸出結(jié)果我們可以看出,兩個(gè)線程共用了臨界資源,我們?cè)谳敵鼋Y(jié)果的時(shí)候可能會(huì)出現(xiàn)不一致,這就源于多個(gè)線程共享數(shù)據(jù)的緣故,因此多線程對(duì)臨界資源的使用可能會(huì)導(dǎo)致數(shù)據(jù)出現(xiàn)誤差。

2. 多線程同步

上面我們說到多個(gè)線程使用同一資源的時(shí)候可能會(huì)引發(fā)數(shù)據(jù)的不一致,所以我們要引入一種互斥機(jī)制來解決這個(gè)問題這種互斥機(jī)制幫助我們?cè)谌我粫r(shí)刻只能由一個(gè)線程訪問同一資源,即使后面排隊(duì)的線程出現(xiàn)了堵塞,鎖定機(jī)制仍然不會(huì)被解除,其余線程仍然無法進(jìn)行資源的訪問。

舉個(gè)例子來說,當(dāng)多個(gè)人排隊(duì)去書店看同一本書的時(shí)候,第一個(gè)人拿到書之后,該書就到了第一個(gè)人的手上,此時(shí)我們就給這本書加了一個(gè)虛擬的鎖,其他讀者只有等待,直到第一個(gè)人結(jié)束閱讀。在Python總我們使用threading模塊中的Lock類來給線程加鎖,Lock的對(duì)象有兩種狀態(tài),默認(rèn)是未鎖定,還有一種鎖定,可以通過acquire()方法鎖定和release()方法解鎖。

操作系統(tǒng)中有一道很經(jīng)典的讀者和寫者問題,多線程進(jìn)行可以進(jìn)行同時(shí)讀,允許多個(gè)讀者進(jìn)行閱讀,但是只允許一個(gè)寫者在寫作,寫者進(jìn)行時(shí)禁止閱讀。

看下面的代碼:

import time
import threading
from threading import Semaphore
import random
writerminute = Semaphore(1)  # 添加計(jì)數(shù)器
readerminute = Semaphore(1)  # 添加計(jì)數(shù)器
readercount = 0
sleept = 1
def reader(i):
    print('讀者' + str(i) + ' 等待閱讀\n', end='')
    readerminute.acquire()  # 計(jì)數(shù)器+1
    global readercount
    if readercount == 0:
        writerminute.acquire()  # 計(jì)數(shù)器+1
    readercount += 1  # 閱讀人數(shù)+1
    readerminute.release()  # 計(jì)數(shù)器-1
    print('讀者' + str(i) + ' 正在閱讀\n', end='')
    time.sleep(sleept)
    print('讀者' + str(i) + ' 結(jié)束閱讀\n', end='')
    readerminute.acquire()
    readercount -= 1  # 讀完-1
    if readercount == 0:
        writerminute.release()
    readerminute.release()
def writer(i):
    print('寫者' + str(i) + ' 等待去寫\n', end='')
    writerminute.acquire()  # +1
    print('寫者' + str(i) + ' 正在寫\n', end='')
    time.sleep(sleept)  # 讀
    print('寫者' + str(i) + ' 完成寫作\n', end='')
    writerminute.release()  # 結(jié)束-1
if __name__ == '__main__':
    list = []
    for i in range(8):
        list.append(random.randint(0, 1))
    print(list)
    # 創(chuàng)建了一個(gè)人數(shù)為8的列表,1為讀者,0為寫者。
    # 首位優(yōu)先進(jìn)行閱讀或?qū)懽?,后續(xù)等待。
    rindex = 1
    windex = 1
    for i in list:
        if i == 0:
            t = threading.Thread(target=reader, args=(rindex,))
            rindex += 1
            t.start()
        else:
            t = threading.Thread(target=writer, args=(windex,))
            windex += 1
            t.start()

運(yùn)行結(jié)果如下:

[1, 0, 0, 1, 1, 1, 0, 0]
寫者1 等待去寫
寫者1 正在寫
讀者1 等待閱讀
讀者2 等待閱讀
寫者2 等待去寫
寫者3 等待去寫
寫者4 等待去寫
讀者3 等待閱讀
讀者4 等待閱讀
寫者1 完成寫作
讀者1 正在閱讀
讀者2 正在閱讀
讀者3 正在閱讀
讀者4 正在閱讀
讀者2 結(jié)束閱讀
讀者3 結(jié)束閱讀
讀者1 結(jié)束閱讀
讀者4 結(jié)束閱讀
寫者2 正在寫
寫者2 完成寫作
寫者3 正在寫
寫者3 完成寫作
寫者4 正在寫
寫者4 完成寫作

在這個(gè)問題上,我們首先對(duì)讀者函數(shù)進(jìn)行理解,首先當(dāng)?shù)谝粋€(gè)線程開始的時(shí)候,讀者開始閱讀,進(jìn)入一個(gè)函數(shù)判斷,如果當(dāng)前沒有讀者在讀,首先把寫者計(jì)數(shù)器給鎖定, 然后進(jìn)入閱讀,讀完之后判斷是否還有讀者在讀,如果沒有人在讀,就解開鎖定。然后 是寫者函數(shù),最后在主程序中,我們通過隨機(jī)數(shù)產(chǎn)生八個(gè)數(shù)字,把1看成讀者,0看成 寫者,第一個(gè)進(jìn)入隊(duì)列的首先進(jìn)行操作,后續(xù)的全部排隊(duì),如果第一個(gè)是寫者,那么后 面的所有人都不能進(jìn)行操作,只有等待,如果第一個(gè)是讀者,那么后面的人先進(jìn)行等待, 然后是讀者優(yōu)先進(jìn)行閱讀。

3. 總結(jié)

本節(jié)的內(nèi)容理解起來比較抽象,結(jié)合著操作系統(tǒng)中的相關(guān)理念能更好的進(jìn)行理解,讀者和寫者是一個(gè)比較經(jīng)典的問題,還有哲學(xué)家進(jìn)餐、一家人吃水果等問題都是線程同步的相關(guān)內(nèi)容,多線程同步的時(shí)候使用Lock對(duì)象能保證線程同步的時(shí)候信息是安全的,也就是多個(gè)線程使用同一資源的時(shí)候,會(huì)確保資源的正確使用。


點(diǎn)贊(0)

C語言網(wǎng)提供由在職研發(fā)工程師或ACM藍(lán)橋杯競賽優(yōu)秀選手錄制的視頻教程,并配有習(xí)題和答疑,點(diǎn)擊了解:

一點(diǎn)編程也不會(huì)寫的:零基礎(chǔ)C語言學(xué)練課程

解決困擾你多年的C語言疑難雜癥特性的C語言進(jìn)階課程

從零到寫出一個(gè)爬蟲的Python編程課程

只會(huì)語法寫不出代碼?手把手帶你寫100個(gè)編程真題的編程百練課程

信息學(xué)奧賽或C++選手的 必學(xué)C++課程

藍(lán)橋杯ACM、信息學(xué)奧賽的必學(xué)課程:算法競賽課入門課程

手把手講解近五年真題的藍(lán)橋杯輔導(dǎo)課程

Dotcpp在線編譯      (登錄可減少運(yùn)行等待時(shí)間)