2009-07-16 42 views
44

Tôi đang học điều kiện chờ đợi và chờ đợi. Theo như tôi có thể nói với một tiểu trình đang chờ điển hình là như thế này:Điều kiện chờ đợi và chờ đợi

pthread_mutex_lock(&m); 
while(!condition) 
    pthread_cond_wait(&cond, &m); 
// Thread stuff here 
pthread_mutex_unlock(&m); 

Những gì tôi không thể hiểu là tại sao dòng while(!condition) là cần thiết ngay cả khi tôi sử dụng pthread_cond_signal() thức dậy thread.

tôi có thể hiểu rằng nếu tôi sử dụng pthread_cond_broadcast() Tôi cần phải kiểm tra điều kiện, bởi vì tôi thức dậy tất cả đề chờ đợi và một trong số họ có thể làm cho tình trạng sai một lần nữa trước khi mở khóa mutex (và do đó chuyển thi khác đều thức dậy mà không nên thực hiện tại thời điểm đó). Nhưng nếu tôi sử dụng pthread_cond_signal() Tôi thức dậy chỉ một chủ đề để điều kiện phải đúng. Vì vậy, mã có thể trông giống như sau:

pthread_mutex_lock(&m); 
pthread_cond_wait(&cond, &m); 
// Thread stuff here 
pthread_mutex_unlock(&m); 

Tôi đọc điều gì đó về tín hiệu giả có thể xảy ra. Đây có phải là (và chỉ này) lý do? Tại sao tôi nên có những người hát giả mạo? Hoặc có cái gì khác tôi không nhận được?

tôi giả sử mã tín hiệu là như thế này:

pthread_mutex_lock(&m); 
condition = true; 
pthread_cond_signal(&cond); // Should wake up *one* thread 
pthread_mutex_unlock(&m); 

Trả lời

43

Lý do thực sự bạn nên đặt pthread_cond_wait trong một vòng lặp while không phải là do đánh thức giả mạo. Ngay cả khi biến điều kiện của bạn không có chế độ đánh thức giả mạo, bạn vẫn sẽ cần vòng lặp để bắt gặp loại lỗi phổ biến. Tại sao? Hãy xem xét những gì có thể xảy ra nếu nhiều luồng đợi trên cùng một điều kiện:

Thread 1       Thread 2   Thread 3 
check condition (fails) 
(in cond_wait) unlock mutex 
(in cond_wait) wait 
           lock mutex 
           set condition 
           signal condvar 
           unlock mutex 
                lock mutex 
                check condition (succeeds) 
                do stuff 
                unset condition 
                unlock mutex 
(in cond_wait) wake up 
(in cond_wait) lock mutex 
<thread is awake, but condition 
is unset> 

Vấn đề ở đây là thread phải phát hành các mutex trước khi chờ đợi, có khả năng cho phép một thread để 'ăn cắp' bất cứ chủ đề đó đã được chờ đợi. Trừ khi nó được đảm bảo rằng chỉ có một chủ đề có thể chờ đợi trên điều kiện đó, nó là không chính xác để giả định rằng điều kiện là hợp lệ khi một thread thức dậy.

+1

chính xác. được bình chọn. điều này sẽ nhận được nhiều sự chú ý hơn câu trả lời được chấp nhận. –

15

Giả sử bạn không kiểm tra điều kiện. Sau đó, thông thường bạn không thể tránh được những điều xấu xảy ra sau (ít nhất, bạn không thể tránh nó trong một dòng mã):

Sender        Receiver 
locks mutex 
sets condition 
signals condvar, but nothing 
    is waiting so has no effect 
releases mutex 
            locks mutex 
            waits. Forever. 

Tất nhiên mã thứ hai ví dụ của bạn có thể tránh điều này bằng cách thực hiện:

pthread_mutex_lock(&m); 
if (!condition) pthread_cond_wait(&cond, &m); 
// Thread stuff here 
pthread_mutex_unlock(&m); 

Sau đó, chắc chắn là trường hợp nếu chỉ có tối đa một người nhận và nếu cond_signal là điều duy nhất có thể đánh thức nó, thì nó sẽ chỉ thức dậy khi điều kiện được thiết lập và do đó sẽ không cần một vòng lặp. nos bao gồm lý do tại sao "if" thứ hai không đúng.

+0

Tôi thấy, do đó, một "nếu" là cần thiết do một lý do logic (chờ đợi vô tận), nhưng một thời gian là thực sự cần thiết do vấn đề thực hiện (tín hiệu giả). – Emiliano

+0

Yea khi lần đầu tiên tôi sử dụng thư viện pthreads, tôi đã hỏi cùng một câu hỏi. Tôi bỏ qua kiểm tra một biến trạng thái và chương trình của tôi sẽ báo hiệu trước khi chờ đợi xảy ra. Đây là toàn bộ các chức năng chờ/tín hiệu. Để chờ và báo hiệu một số thay đổi được bảo vệ bằng mutex trong trạng thái bộ nhớ. –

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