2013-06-03 21 views
22

Tôi đang sử dụng biến có điều kiện để dừng luồng cho đến khi một luồng khác đã xử lý xong hàng đợi nhiệm vụ của nó (câu chuyện dài). Vì vậy, trên một thread Tôi khóa và chờ đợi:Làm cách nào để sử dụng biến điều kiện tăng để đợi một chuỗi hoàn tất xử lý?

boost::mutex::scoped_lock lock(m_mutex); 
m_condition.wait(lock); 

Khi thread khác đã hoàn thành nhiệm vụ của nó, nó báo hiệu thread chờ đợi như sau:

boost::mutex::scoped_lock lock(m_parent.m_mutex); 
m_parent.m_condition.notify_one(); 

Vấn đề tôi đang nhìn thấy là sự chờ đợi thread không ngừng chờ đợi trừ khi tôi đặt một breakpoint trên các hướng dẫn sau nó (tôi đang sử dụng xcode, fyi). Vâng, điều này có vẻ lạ. Có ai biết tại sao điều này có thể xảy ra không? Tôi có sử dụng sai biến điều kiện không?

+0

Mã này là một chút bối rối ... là lần đầu tiên 'm_mutex' trường hợp tương tự như thứ hai' m_parent.m_mutex'? –

Trả lời

42

Có, bạn đang sử dụng sai biến điều kiện. "Biến điều kiện" thực sự chỉ là cơ chế báo hiệu. Bạn cũng cần phải thử nghiệm một điều kiện. Trong trường hợp của bạn, điều có thể xảy ra là luồng đang gọi notify_one() thực sự hoàn tất trước khi chuỗi gọi wait() thậm chí bắt đầu. (Hoặc ít nhất, cuộc gọi notify_one() đang diễn ra trước cuộc gọi wait().) Đây được gọi là "đánh thức bị nhỡ".

Giải pháp là để thực sự có một biến, trong đó có điều kiện mà bạn quan tâm:

bool worker_is_done=false; 

boost::mutex::scoped_lock lock(m_mutex); 
while (!worker_is_done) m_condition.wait(lock); 

boost::mutex::scoped_lock lock(m_mutex); 
worker_is_done = true; 
m_condition.notify_one(); 

Nếu worker_is_done==true trước các chủ đề khác thậm chí bắt đầu chờ đợi sau đó bạn chỉ sẽ rơi ngay qua vòng lặp while mà không bao giờ gọi wait().

Mẫu này rất phổ biến đến nỗi tôi gần như muốn nói rằng nếu bạn không có vòng lặp while gói condition_variable.wait() thì bạn luôn có lỗi. Trong thực tế, khi C++ 11 thông qua một cái gì đó tương tự như boost :: condtion_variable họ thêm một loại mới của wait() mà phải mất một biểu ngữ lambda (về cơ bản nó làm while vòng lặp cho bạn):

std::condition_variable cv; 
std::mutex m; 
bool worker_is_done=false; 


std::unique_lock<std::mutex> lk(m); 
cv.wait(lk, []{return worker_is_done;}); 
+0

'boost :: mutex :: scoped_lock lock (m_mutex);' trong chuỗi chờ đợi cần thiết cho là gì? notify_one() không lấy args. – ItsmeJulian

+0

Nó ở đó để cung cấp một ghi nguyên tử cho 'worker_is_done'. Cách khác là khai báo kiểu 'nguyên tử 'thay vì chỉ' bool'. –

+0

@DavidStone Điều gì xảy ra nếu chúng ta đang chạy mã trên một bộ xử lý trong đó 1 phép gán byte là ví dụ nguyên tử. x86? Chúng ta sẽ không cần khóa trong trường hợp đó, phải không? – user3286661

2

Tôi đã thực hiện một ví dụ minh họa cách sử dụng điều kiện tăng cường, dựa vào thảo luận.

#include <iostream> 

#include <boost/asio.hpp> 
#include <boost/thread/mutex.hpp> 
#include <boost/thread/thread.hpp> 

boost::mutex io_mutex; 
bool worker_is_done = false; 
boost::condition_variable condition; 

void workFunction() 
{ 
    std::cout << "Waiting a little..." << std::endl; 
    boost::this_thread::sleep(boost::posix_time::seconds(1)); 
    worker_is_done = true; 
    std::cout << "Notifying condition..." << std::endl; 
    condition.notify_one(); 
    std::cout << "Waiting a little more..." << std::endl; 
    boost::this_thread::sleep(boost::posix_time::seconds(1)); 
} 

int main() 
{ 
    boost::mutex::scoped_lock lock(io_mutex); 
    boost::thread workThread(&workFunction); 

    while (!worker_is_done) condition.wait(lock); 
    std::cout << "Condition notified." << std::endl; 
    workThread.join(); 
    std::cout << "Thread finished." << std::endl; 

    return 0; 
} 

Boost condition variable example

+3

Bạn không nên lấy khóa tại nơi làm việcChức năng trước khi thiết lập worker_is_done thành true? –

+0

Tôi nghĩ anh ấy nên làm vậy. –

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