2010-09-16 45 views
11

我是Boost庫的新手,並且試圖實現在共享隊列上運行的簡單生產者和消費者線程。我的示例實現是這樣的:使用boost :: lock_guard進行簡單的共享數據鎖定

#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; 
} 

此代碼運行如我所料,但是當main退出,我得到

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

(我不知道如果從consumer輸出有關在位置,但我已經離開了。)

我在使用Boost時做錯了什麼?

回答

8

你給你的線程(生產者&消費者)的mutex對象,然後分離它們。他們應該永遠運行。然後退出程序,並且mutex對象不再有效。儘管如此,你的線程仍然嘗試使用它,他們不知道它不再有效。如果你使用NDEBUG定義你會得到一個coredump。

你是否試圖編寫一個守護進程應用程序,這是脫離線程的原因?

+0

我不想寫任何特定類型的應用程序 - 我只是試圖熟悉Boost.Thread庫。快速調試會話期間調用'detach';如果我刪除它們,行爲是相同的。我最初懷疑在程序退出之前需要停止線程,因此需要「分離」調用。 – kfb 2010-09-16 12:54:33

+7

不要立即從主線程退出,也不要分離消費者和生產者。在主線程中等待,直到你的消費者和生產者工作。當他們完成時加入他們。然後從main退出。 – 2010-09-16 13:08:43

+0

這是有道理的,並且確實停止斷言,謝謝! – kfb 2010-09-16 13:31:27

9

有點偏離主題,但相關的imo(......在評論中等待火焰)。

這裏的消費者模型非常貪婪,循環和檢查隊列上的數據不斷。如果你的消費者線程在有數據可用時確定性地喚醒,那麼使用線程間信號而不是這個鎖定和窺視循環會更有效率(浪費更少的CPU週期)。想想這樣:當隊列是空的,這實質上是一個緊密的循環,只是由於需要獲取鎖而破壞了。不理想?

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(); 
     } 
    } 
} 

據我所知,你正在學習,但我不會建議在「真實」的代碼中使用了這一點。儘管學習圖書館,但沒關係。值得讚揚的是,這是一個比理解如何使用lock_guard更爲複雜的例子,所以你的目標很高!

最終,您最有可能爲需要工作的工作人員發出信號的隊列構建(或更好(如果可用,重用))代碼,然後您將在工作線程中使用lock_guard調解對共享數據的訪問。

+0

題外話,但肯定有用的信息,謝謝!我同意這是一個非常貪婪的消費者,但是這源於一個早期的測試,其中沒有同步,我試圖鼓勵該程序鎖定:) – kfb 2010-09-16 13:30:49

5

main退出時,所有全局對象都被銷燬。然而,你的線程會繼續運行。因此,您最終遇到了問題,因爲線程正在訪問已刪除的對象。

底線是您必須在退出之前終止線程。唯一的做法是讓主程序等待(通過使用boost::thread::join),直到線程完成運行。您可能想要提供某種方式來指示線程完成運行以節省等待時間太長。

另一個問題是即使沒有數據,消費者線程也會繼續運行。您可能需要等待boost::condition_variable,直到發出有新數據的信號。