Barrier objects (đối tượng rào cản) trong Python được sử dụng để chờ cho một số lượng cố định các thread – luồng thực thi xong, trước khi bất kỳ thread cụ thể nào khác có thể thực thi tiếp chương trình. Mỗi thread sẽ gọi đến hàm wait() khi đạt đến barrier – rào cản. Barrier – rào cản sẽ chịu trách nhiệm cho việc theo dõi và ghi nhớ số lượng các lời gọi hàm wait(). Nếu số lượng các lời gọi hàm wait() này vượt quá số lượng các threads đã được khởi tạo cùng với barrier – rào cản, thì tất cả các threads tại thời điểm thực thi này, đều sẽ được giải phóng đồng thời, và barrier sẽ trả lại quyền tiếp tục thực thi chương trình cho các waiting threads – các luồng đang đợi để được thực thi.

Các barriers thậm chí còn có thể được sử dụng để truy cập một cách đồng bộ giữa các threads. Tuy nhiên, thường thì barrier sẽ được sử dụng để kết hợp output – đầu ra của các threads lại với nhau. Một barrier object (đối tượng rào cản) có thể được tái sử dụng nhiều lần cho cùng một số lượng chính xác các threads mà nó đã được khởi tạo ban đầu.

1. Khởi tạo một barrier

Một barrier có thể được khởi tạo bằng cách sử dụng lớp threading.Barrier như được thể hiện trong đoạn code ví dụ bên dưới đây. Con số nằm trong cặp dấu ngoặc đơn đại diện cho số lượng các threads mà barrier nên chờ.

Cú pháp khởi tạo barrier object trong Python:

barrier = threading.Barrier(number_of_threads, action = None, timeout = None)

Cú pháp trên sẽ tạo ra một barrier object cho number_of_threads. Tham số thứ hai  action, là một callable, được gọi đến bởi một trong số các threads, khi chúng được giải phóng. Tham số thứ ba timeout là giá trị thời gian chờ mặc định nếu không có giá trị nào được chỉ định cho phương thức wait().

# -----------------------------------------------------------
#Cafedev.vn - Kênh thông tin IT hàng đầu Việt Nam
#@author cafedevn
#Contact: cafedevn@gmail.com
#Fanpage: https://www.facebook.com/cafedevn
#Group: https://www.facebook.com/groups/cafedev.vn/
#Instagram: https://instagram.com/cafedevn
#Twitter: https://twitter.com/CafedeVn
#Linkedin: https://www.linkedin.com/in/cafe-dev-407054199/
#Pinterest: https://www.pinterest.com/cafedevvn/
#YouTube: https://www.youtube.com/channel/UCE7zpY_SlHGEgo67pHxqIoA/
# -----------------------------------------------------------

import threading 
  
barrier = threading.Barrier(3) 
  
class thread(threading.Thread): 
    def __init__(self, thread_ID): 
        threading.Thread.__init__(self) 
        self.thread_ID = thread_ID 
    def run(self): 
        print(str(self.thread_ID) + "\n") 
        barrier.wait() 
          
thread1 = thread(100) 
thread2 = thread(101) 
  
thread1.start() 
thread2.start() 
barrier.wait() 
  
print("Exit\n") 

Kết quả in ra là:

100
101
Exit

Có thể kể đến một số lệnh gọi hàm phổ biến, liên quan đến lớp threading.Barrier là:

1.1 Kiểm tra trạng thái của barrier:

broken: Là một giá trị boolean, là True nếu barrier đang ở trong trạng thái broken – barrier (rào cản) đã bị phá vỡ.

Cú pháp:

barrier.broken

1.2. parties: Số lượng các threads cần phải truyền vào cho barrier.

Cú pháp:

barrier.parties

1.3. Hủy bỏ một barrier:

abort: Đưa barrier vào trong trạng thái broken – đã bị phá vỡ. Điều này sẽ làm cho bất kỳ những lời gọi nào đang có hiệu lực, hoặc những lời gọi trong tương lai tới hàm wait() bị thất bại, với lỗi BrokenBarrierError

Việc gọi tới hàm abort() trên barrier thường được sử dụng để bỏ qua các điều kiện bế tắc (conditions of deadlocking) trong khi thực thi chương trình.

Cú pháp:

barrier.abort()

1.4. Khởi động lại barrier:

reset: Trả barrier về trạng thái trống (empty state) mặc định. Bấy kỳ threads nào đang chờ trên barrier đó đều sẽ nhận được ngoại lệ BrokenBarrierError.

Cú pháp:

barrier.reset()

1.5. wait: Vượt qua barrier – rào cản.

Khi tất cả các threads đang tham gia vào barrier gọi đến hàm này, tất cả chúng đều sẽ được giải phóng đồng thời. Ngoài ra, nếu có giá trị timeout – thời gian chờ được cung cấp, giá trị timeout đó sẽ được ưu tiên sử dụng. Giá trị trả về của hàm này là một số nguyên integer nằm trong khoảng từ 0 cho đến số lượng các threads – 1, khác nhau đối với mỗi thread. Nếu lời gọi hàm này bị times out – hết thời gian chờ, trạng thái của barrier sẽ được đặt thành broke – đã bị phả vỡ. Phương thức này có thể đưa ra ngoại lệ BrokenBarrierError nếu barrier bị phá vỡ hoặc bị khởi động lại (reset) trong khi một thread đang chờ đợi.

Cú pháp:

barrier.wait(timeout = None)

6. n_waiting: Số lượng các threads hiện tại đang chờ đợi trên barrier.

Cú pháp:

barrier.n_waiting

Thông thường, khi một barrier object được reset – khởi động lại, hoặc bị broken – phá vỡ, ngoại lệ BrokenBarrierError sẽ được đưa ra.

Dưới đây là đoạn chương trình ví dụ, mô tả cách các barriers được sử dụng trong Python:


# program to demonstrate 
# barriers in python 
  
import threading 
  
barrier = threading.Barrier(3) 
  
class thread(threading.Thread): 
    def __init__(self, thread_ID): 
        threading.Thread.__init__(self) 
        self.thread_ID = thread_ID 
    def run(self): 
        print(str(self.thread_ID) + "\n") 
        print("Parties = " + str(barrier.parties) + "\n") 
        print("n_waiting = " + str(barrier.n_waiting) + "\n") 
        barrier.wait() 
          
thread1 = thread(100) 
thread2 = thread(101) 
  
thread1.start() 
thread2.start() 
  
barrier.wait() 
  
print(str(barrier.broken) + "\n") 
barrier.reset() 
print("n_waiting after reset = " + str(barrier.n_waiting)) 
barrier.abort() 
print("End") 

Kết quả in ra là:

100
101
Parties = 3
Parties = 3
n_waiting = 1
n_waiting = 1
False
n_waiting after reset = 0
End

Nguồn và Tài liệu tiếng anh tham khảo:

Tài liệu từ cafedev:

Nếu bạn thấy hay và hữu ích, bạn có thể tham gia các kênh sau của cafedev để nhận được nhiều hơn nữa:

Chào thân ái và quyết thắng!

Đăng ký kênh youtube để ủng hộ Cafedev nha các bạn, Thanks you!