2010-09-16 28 views
11

Tôi là người mới đến thư viện Boost và đang cố triển khai một luồng sản xuất và tiêu dùng đơn giản hoạt động trên hàng đợi được chia sẻ. Ví dụ thực hiện của tôi trông như thế này:Sử dụng boost :: lock_guard để khóa dữ liệu chia sẻ đơn giản

#include <iostream> 
#include <deque> 
#include <boost/thread.hpp> 

boost::mutex mutex; 
std::deque<std::string> queue; 

void producer() 
{ 
    while (true) { 
     boost::lock_guard<boost::mutex> lock(mutex); 

     std::cout << "producer() pushing string onto queue" << std::endl; 

     queue.push_back(std::string("test")); 
    } 
} 

void consumer() 
{ 
    while (true) { 
     boost::lock_guard<boost::mutex> lock(mutex); 

     if (!queue.empty()) { 
      std::cout << "consumer() popped string " << queue.front() << " from queue" << std::endl; 

      queue.pop_front(); 
     } 
    } 
} 

int main() 
{ 
    boost::thread producer_thread(producer); 
    boost::thread consumer_thread(consumer); 

    sleep(5); 

    producer_thread.detach(); 
    consumer_thread.detach(); 

    return 0; 
} 

Mã này chạy như tôi mong đợi, nhưng khi main thoát, tôi nhận được

/usr/include/boost/thread/pthread/mutex.hpp:45:  
    boost::mutex::~mutex(): Assertion `!pthread_mutex_destroy(&m)' failed. 
consumer() popped string test from queue 
Aborted 

(Tôi không chắc chắn nếu đầu ra từ consumer là có liên quan trong đó vị trí, nhưng tôi đã để nó vào.)

Tôi có làm điều gì sai trong việc sử dụng Boost không?

Trả lời

8

Bạn cung cấp cho các chủ đề của bạn (nhà sản xuất & người tiêu dùng) các đối tượng mutex và sau đó tách chúng ra. Họ được cho là sẽ chạy mãi mãi. Sau đó, bạn thoát khỏi chương trình của mình và đối tượng mutex không còn hợp lệ. Tuy nhiên các chủ đề của bạn vẫn cố gắng sử dụng nó, họ không biết rằng nó không còn hợp lệ nữa. Nếu bạn đã sử dụng NDEBUG xác định bạn sẽ có một coredump.

Bạn đang cố gắng viết một ứng dụng daemon và đây là lý do để tách luồng?

+0

Tôi không cố gắng viết bất kỳ loại ứng dụng cụ thể nào — tôi chỉ đang cố gắng làm quen với thư viện Boost.Thread. Các cuộc gọi đến 'tách 'được đưa vào trong một phiên gỡ lỗi nhanh; hành vi là giống hệt nhau nếu tôi xóa chúng.Ban đầu tôi nghi ngờ rằng các chủ đề cần phải được dừng lại trước khi chương trình đã thoát, do đó các cuộc gọi 'tách '. – kfb

+7

Không thoát khỏi chủ đề chính ngay lập tức và không tách người tiêu dùng và nhà sản xuất. Đợi trong chuỗi chính cho đến khi người tiêu dùng và nhà sản xuất của bạn hoạt động. Và khi họ kết thúc họ. Và sau đó thoát khỏi chính. –

+0

Điều đó có ý nghĩa và không ngừng khẳng định, cảm ơn! – kfb

9

Một chút ngoài chủ đề nhưng có liên quan imo (... chờ ngọn lửa trong nhận xét).

Mô hình người tiêu dùng ở đây rất tham lam, lặp và kiểm tra dữ liệu trên hàng đợi liên tục. Nó sẽ hiệu quả hơn (lãng phí ít chu kỳ CPU) nếu bạn có các luồng tiêu thụ của bạn được đánh thức một cách xác định khi dữ liệu có sẵn, sử dụng tín hiệu liên thread thay vì vòng khóa và xem này. Hãy suy nghĩ về nó theo cách này: trong khi hàng đợi là trống rỗng, điều này về bản chất là một vòng lặp chặt chẽ chỉ bị phá vỡ bởi sự cần thiết để có được khóa. Không lý tưởng?

void consumer() 
{ 
    while (true) { 
     boost::lock_guard<boost::mutex> lock(mutex); 

     if (!queue.empty()) { 
      std::cout << "consumer() popped string " << queue.front() << " from queue" << std::endl; 

      queue.pop_front(); 
     } 
    } 
} 

Tôi hiểu rằng bạn đang học nhưng tôi không khuyên bạn nên sử dụng mã này trong mã 'thực'. Tuy nhiên, đối với việc học thư viện, nó vẫn ổn. Để tín dụng của bạn, đây là một ví dụ phức tạp hơn cần thiết để hiểu làm thế nào để sử dụng lock_guard, vì vậy bạn đang hướng tới cao!

Cuối cùng, bạn sẽ xây dựng (hoặc tốt hơn nếu có sẵn, sử dụng lại) mã cho hàng đợi báo hiệu người lao động khi họ được yêu cầu làm việc và sau đó bạn sẽ sử dụng lock_guard bên trong chuỗi công việc của mình để dàn xếp quyền truy cập vào dữ liệu được chia sẻ .

+0

Tắt chủ đề, nhưng chắc chắn thông tin hữu ích, cảm ơn! Tôi đồng ý rằng đây là một người tiêu dùng rất tham lam, nhưng điều này bắt nguồn từ một thử nghiệm trước đó trong đó không có đồng bộ hóa và tôi đã cố gắng khuyến khích chương trình để khóa :) – kfb

5

Khi thoát khỏi main, tất cả các đối tượng trên toàn cầu đều bị hủy. Chủ đề của bạn, tuy nhiên, vẫn tiếp tục chạy. Do đó bạn kết thúc với các vấn đề bởi vì các chủ đề đang truy cập một đối tượng đã xóa.

Điểm mấu chốt là bạn phải chấm dứt chuỗi trước khi thoát. Điều duy nhất để làm điều này mặc dù là để có được chương trình chính để chờ đợi (bằng cách sử dụng một boost::thread::join) cho đến khi các chủ đề đã kết thúc chạy. Bạn có thể muốn cung cấp một số cách báo hiệu các luồng để kết thúc chạy để tiết kiệm từ việc chờ đợi quá lâu.

Vấn đề khác là chuỗi người tiêu dùng của bạn tiếp tục chạy ngay cả khi không có dữ liệu. Bạn có thể muốn đợi trên boost::condition_variable cho đến khi báo hiệu rằng có dữ liệu mới.

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