Condition條件變數

昀溪發表於2018-12-09

條件變數是一種比較複雜的執行緒同步機制

#!/usr/bin/env python
# -*- coding: utf-8 -*-


"""
條件變數,執行緒間通訊提供的另一種鎖,用於複雜的執行緒同步鎖。

A先說話,B回答,也就是你一句我一句這種形式,你使用單純的執行緒無法實現,就需要使用condition,Condition其實本質還是使用Rlock,當然你可以指定使用Lock,
實現的關鍵是Contition的wati和notify這兩個函式。
"""

import threading
from threading import Condition


class A(threading.Thread):
    def __init__(self, condition, num):
        self.condition = condition
        self.num = num
        super().__init__(name="A")

    def run(self):
        with self.condition:
            for i in range(self.num):
                print("A say: %s + %s 等於多少 ?" % (str(i), str(i)))
                self.condition.notify()
                self.condition.wait()


class B(threading.Thread):
    def __init__(self, condition, num):
        self.condition = condition
        self.num = num
        super().__init__(name="B")

    def run(self):
        self.condition.acquire() # 必須先獲得鎖才可以呼叫wait或者notify
        # with self.condition:  # 這裡沒有使用with,其實如果不使用with你就手動加鎖,然後釋放。使用with就幫你自動完成,這就和 with open()自動關閉檔案流式一樣的。
        for i in range(self.num):
            self.condition.wait()
            print("B say: %s + %s 等於 %s." % (str(i), str(i), str(i+i)))
            self.condition.notify()
        self.condition.release()

if __name__ == '__main__':
    condition = Condition()
    a = A(condition, 5)
    b = B(condition, 5)

    """
    這裡要注意,雖然是a先說話,但是要先啟動b,使用了condition的話執行緒的啟動順序很重要。如果先啟動a,那麼就會一直卡住。為什麼?
    先啟動a,那麼就會先執行notify,而b還沒有啟動也就意味著沒有wait,所以卡住了,也就是說notify的前提是先有wait才可以。換句話
    說就是你要通知就得先有人在等,在沒人等的情況下你通知了這樣你就無法獲得回覆所以就一直卡在那裡。所以先啟動b就是先等待,然後啟動a
    a說完話就通知,這樣b可以收到然後處理,然後b回覆,之後喚醒a,這樣相繼執行。
    其實Condition和event是類似的可以理解為基於事件的通知機制。

    注意事項: 1. 先呼叫 with self.condition 或者是 acquire() 也就是先加鎖才可以使用wait和notify
             2. 如果手動加鎖之後要手動釋放
             3. 執行緒啟動順序很重要
    """
    b.start()
    a.start()

 

相關文章