2008-09-16 29 views
41

Ưu điểm/nhược điểm của việc sử dụng pthread_cond_wait hoặc sử dụng semaphore là gì? Tôi đang chờ đợi một sự thay đổi trạng thái như thế này:pthread_cond_wait so với semaphore

pthread_mutex_lock(&cam->video_lock); 
while(cam->status == WAIT_DISPLAY) { 
    pthread_cond_wait(&cam->video_cond, &cam->video_lock); 
} 
pthread_mutex_unlock(&cam->video_lock); 

Sử dụng một semaphore được khởi tạo đúng, tôi nghĩ rằng tôi có thể làm điều đó như thế này:

while(cam->status == WAIT_DISPLAY) { 
    sem_wait(&some_semaphore); 
} 

những ưu và nhược điểm của từng phương pháp là gì?

+0

Tôi vừa nhận ra rằng "semaphore được khởi tạo đúng" không được xác định. Là semaphore đặt thành 1 hoặc 0? Tôi muốn nói nó nên được thiết lập để 0. Sau đó, không semaphore bảo vệ cam-> tình trạng hay không? – Blaisorblade

+0

Trong đoạn thứ hai, như đã đề cập trong các câu trả lời khác, chuỗi của bạn sẽ bị chặn trong khi mutex không được phát hành. Vì vậy, phương thức 'sem_wait' của bạn sẽ không bao giờ trở lại bởi vì không có luồng nào khác có thể có được mutex và gọi' sem_signal'. Tuy nhiên, tôi sẽ không làm gì nếu tôi phát hành mutex trước 'sem_wait' và yêu cầu nó một lần nữa sau khi chờ đợi. Tôi biết những bước này không phải là nguyên tử, vậy điều gì sẽ xảy ra? – sevenkplus

Trả lời

58

Một semaphore phù hợp với mô hình người tiêu dùng sản xuất, mặc dù nó có các ứng dụng khác. Logic chương trình của bạn chịu trách nhiệm đảm bảo rằng số lượng bài đăng phù hợp được thực hiện cho số lần chờ. Nếu bạn đăng một semaphore và không ai đang chờ đợi nó, sau đó khi họ chờ đợi họ tiếp tục ngay lập tức. Nếu vấn đề của bạn là như vậy mà nó có thể được giải thích về giá trị đếm của một semaphore, sau đó nó sẽ được dễ dàng để giải quyết với một semaphore.

Biến điều kiện có thể tha thứ hơn một chút ở một số khía cạnh. Ví dụ, bạn có thể sử dụng cond_broadcast để đánh thức tất cả các bồi bàn, không có nhà sản xuất biết có bao nhiêu người. Và nếu bạn cond_signal một condvar với không ai chờ đợi trên nó thì không có gì xảy ra. Điều này là tốt nếu bạn không biết liệu sẽ có một người nghe thích thú không. Đó cũng là lý do tại sao người nghe nên luôn luôn kiểm tra trạng thái với mutex được tổ chức trước khi chờ đợi - nếu họ không thì họ có thể bỏ lỡ một tín hiệu và không thức dậy cho đến khi một kế tiếp (mà có thể không bao giờ).

Vì vậy, biến điều kiện phù hợp để thông báo cho các bên quan tâm rằng trạng thái đã thay đổi: bạn có được mutex, thay đổi trạng thái, tín hiệu (hoặc phát sóng) condvar và giải phóng mutex. Nếu điều này mô tả vấn đề của bạn, bạn đang ở trong lãnh thổ condvar. Nếu người nghe khác nhau quan tâm đến các tiểu bang khác nhau, bạn có thể phát sóng và họ sẽ lần lượt thức dậy, tìm hiểu xem họ có tìm thấy trạng thái mà họ muốn hay không và nếu không đợi lại.

Nó thực sự rất gnarly để cố gắng loại điều này với một mutex và semaphore một. Vấn đề xảy ra khi bạn muốn thực hiện mutex, kiểm tra một số trạng thái, sau đó chờ trên semaphore để thay đổi. Trừ khi bạn có thể giải phóng nguyên tử mutex và chờ đợi trên semaphore (mà trong pthreads bạn không thể), bạn kết thúc chờ đợi trên semaphore trong khi giữ mutex. Điều này ngăn chặn các mutex, có nghĩa là những người khác không thể lấy nó để làm cho sự thay đổi bạn quan tâm. Vì vậy, bạn sẽ bị cám dỗ để thêm một mutex khác theo cách phụ thuộc vào các yêu cầu cụ thể của bạn. Và có lẽ một semaphore khác. Kết quả thường là mã không chính xác với các điều kiện chủng tộc có hại.

Biến điều kiện thoát khỏi vấn đề này, bởi vì gọi cond_wait tự động giải phóng mutex, giải phóng nó để người khác sử dụng. Các mutex được lấy lại trước khi cond_wait trả về.

IIRC có thể thực hiện một loại condvar chỉ sử dụng semaphores, nhưng nếu mutex bạn đang thực hiện để đi với condvar là cần thiết để có trylock, sau đó nó là một head-scratcher nghiêm trọng, và chờ đợi thời gian được ra . Không được khuyến khích. Vì vậy, đừng cho rằng bất cứ điều gì bạn có thể làm với một condvar có thể được thực hiện với semaphores. Thêm vào đó tất nhiên các mutex có thể có những hành vi tốt đẹp mà semaphores thiếu, chủ yếu là ưu tiên đảo ngược tránh.

0

Trong đoạn mã thứ hai, bạn sẽ nhận được vô số lần khóa, không bao giờ phát hành nó.

Nói chung, trạng thái bạn đang mờ nhạt có thể được biểu thị hoàn toàn bằng một semaphore, sau đó bạn có thể sử dụng nó. Cấu trúc khóa có kích thước nhỏ hơn và đòi hỏi ít hoạt động nguyên tử hơn để kiểm tra/thiết lập/giải phóng.

Nếu không, nếu trạng thái phức tạp và các phần khác nhau của mã chờ trên các điều kiện khác nhau của cùng một biến (ví dụ, tại đây bạn muốn x < 10; ở đó bạn muốn y> x), hãy dùng cond_wait.

+0

Đoạn thứ 2 là chính xác - một sự thức tỉnh luôn do một người nào đó báo hiệu semaphore. – Blaisorblade

+0

@Blaisorblade, đánh thức là chính xác, kiểm tra tình trạng là không vì nó không được bảo vệ. –

+0

Đó là một vấn đề khác với câu trả lời này mô tả - "trong đoạn thứ hai của bạn, bạn sẽ nhận được vô số lần khóa, không bao giờ giải phóng nó". Tôi đề cập đến vấn đề này trong câu trả lời của tôi ở trên (mặc dù không phải rất cụ thể). Nhưng trong khi nhìn lại mã, tôi nhận ra rằng người ta không thể thực sự biết liệu đoạn thứ hai là chính xác hay không vì thiếu quá nhiều chi tiết (xem bình luận của tôi cho câu hỏi). Nhưng tôi đã nói sai ý kiến ​​của tôi không chính xác - tôi nên nói "vấn đề bạn đề cập không có ở đó, bởi vì ...". – Blaisorblade

19

Điều kiện cho phép bạn thực hiện một số điều mà semaphores sẽ không.

Ví dụ: giả sử bạn có một số mã yêu cầu một mutex, được gọi là m. Tuy nhiên nó cần phải đợi cho đến khi một số luồng khác hoàn thành nhiệm vụ của chúng, vì vậy nó đợi trên một semaphore gọi là s. Bây giờ bất kỳ chủ đề nào cần m bị chặn chạy, mặc dù chuỗi có m đang chờ trên s. Những loại tình huống có thể được giải quyết bằng cách sử dụng điều kiện. Khi bạn chờ đợi trên một điều kiện, mutex hiện đang nắm giữ được phát hành, do đó, các chủ đề khác có thể có được mutex. Vì vậy, quay lại ví dụ của chúng tôi và giả sử có điều kiện c đã được sử dụng thay vì s. Chuỗi của chúng tôi hiện mua lại m và sau đó chờ điều kiện theo số c. Bản phát hành này m để các chủ đề khác có thể tiếp tục. Khi c khả dụng, m được phản hồi và chuỗi ban đầu của chúng tôi có thể tiếp tục vui vẻ trên đường đi.

Biến điều kiện cũng cho phép bạn để tất cả các chủ đề đang chờ trên biến có điều kiện để tiếp tục qua pthread_cond_broadcast. Ngoài ra, nó cũng cho phép bạn thực hiện chờ đợi thời gian để bạn không phải chờ đợi mãi mãi.

Tất nhiên, đôi khi bạn không cần biến có điều kiện, do đó, tùy thuộc vào yêu cầu của bạn, một hoặc khác có thể tốt hơn.

+3

Đây là câu trả lời hay. Để thêm vào mô tả, điều làm cho điều kiện duy nhất liên quan đến sự kết hợp được mô tả của mutex và semaphore là điều kiện điều khiển cặp mutex/semaphore một cách nguyên tử !! –

4

Đoạn thứ hai không phù hợp, đừng làm vậy.

Các câu trả lời khác có một cuộc thảo luận tốt đẹp về các giá trị tương đối; Tôi sẽ chỉ thêm rằng pthread_cond_broadcast là một lợi thế rõ ràng của các biến điều kiện. Ngoài ra, tôi chỉ quen với các biến điều kiện cho điều đó, vì chúng là những gì bạn sử dụng trong Java, thậm chí vì chúng giúp bạn tránh được các cuộc đua khi kiểm tra các cờ được chia sẻ.

Thật vậy, trong đoạn thứ 2 bạn không có bất kỳ khóa bảo vệ đọc cam -> trạng thái, vì vậy nó được truy cập thông qua một cuộc đua dữ liệu. Hầu hết các nền tảng sẽ cho phép bạn thoát khỏi điều đó trong ví dụ cụ thể này, nhưng điều đó có ngữ nghĩa không xác định, bởi POSIX và theo mô hình bộ nhớ của các tiêu chuẩn C/C++ tiếp theo.

Trên thực tế, điều kiện cuộc đua thực sự là có thể nếu một luồng khác phân bổ cấu trúc cam mới và ghi đè cam; thread chờ đợi có thể thấy cập nhật cho con trỏ 'cam' mà không thấy khởi tạo trạng thái cam. Thật vậy, đoạn thứ hai là yêu cầu cho sự cố, trong trường hợp này và nói chung.

http://www.hpl.hp.com/personal/Hans_Boehm/c++mm/

+0

Trong thực tế, trong đoạn thứ hai, semaphore có thể bảo vệ (hoặc không) cờ trạng thái (mặc dù tôi không thể tưởng tượng một giao thức khóa tốt cho điều đó). – Blaisorblade

Các vấn đề liên quan