2012-08-27 89 views
3

這是我第一次嘗試使用std::future這段代碼爲什麼會產生競態條件?

我有三個不同的文件,我想同時解析。有三個功能可以做到這一點,稱爲parseSentences,parseTagsparseLinks。通過使用一個非常簡單的lambda函數[]() { parser->function(); },其中parser是一個靜態變量,函數是我之前命名的三個函數之一,它們中的每一個都使用std::async單獨的線程啓動。

int parser::start() 
{ 
    int ret = SUCCESS; 
    ASSERT(m_output != nullptr); 
    static parser * thisParserInstance = this; 

    // parsing files 
    std::future<int> parseSentence = std::async(std::launch::async, []() { return thisParserInstance->parseSentences(); }); 
    std::future<int> parseLinksResult = std::async(std::launch::async, []() { return thisParserInstance->parseLinks(); }); 
    std::future<int> parseTagsResult = std::async(std::launch::async, []() { return thisParserInstance->parseTags(); }); 

    // retrieving the results 
    ret = parseSentence.get(); 
    const int linksResult = parseLinksResult.get(); 
    const int tagsResult = parseTagsResult.get(); 

    if (ret == SUCCESS) 
     ret = linksResult == SUCCESS ? tagsResult : linksResult; 

    return ret; 
} 

現在,當我在gdb運行我的程序,分段錯誤發生在std::future局部變量之一的破壞。當前有2個線程正在運行。 線程#1的調用棧是here。 線程#2的調用棧是here

請注意,第一個調用堆棧中指向this的指針爲空,導致分段錯誤。

如果有人有線索,我會很感激。

+3

沒有看這個bug,這個設計看起來仍然很可怕。 'thisParserInstance'存在什麼?它的名字是不正確的:它是第一個進入該函數的實例,* forever *。爲什麼不直接使用'this'? – GManNickG

+1

爲什麼這麼複雜?只需將'[this]'放入捕獲列表中... –

+0

@GManNickG我應該解釋這一點。該功能在程序執行過程中只調用一次。我需要將解析器實例傳遞給3個新線程,並且我看不到任何更乾淨的方法。 – qdii

回答

3

的一個大問題是在這裏:

static parser * thisParserInstance = this; 

這是初始化第一次調用該函數,然後保持不變的未來調用。所以,如果你在一個對象上調用該函數,銷燬該對象,然後在第二個對象上調用它,你實際上正在處理一個懸掛對象的懸掛指針。這肯定會給未定義的行爲。

沒有理由使用靜態變量; lambda可以捕獲this並對正確的對象起作用。或者更簡單地說,作爲意見提出,使用async一個可變形式結合this的成員函數:

std::async(std::launch::async, &parser::parseSentences, this); 
+0

+1,謝謝。我會改變這種情況,但這不能成爲bug,因爲這個功能只是被故意調用一次。 – qdii

+0

不管怎樣,儘管你不認爲它會有幫助,但試試捕獲這個ptr。我想你可能會感到驚訝。 –

+4

無論如何,'std :: async(std :: launch :: async,&parser :: parseSentences,this)'不需要使用lambda;'會正常工作。 –

1

對不起球員。

這裏是解決方案:std::future exception on gcc experimental implementation of C++0x

-lpthread鏈接之後,錯誤消失。感謝您的其他評論,但他們非常有幫助。

+0

我懷疑std :: future沒有引入內存障礙。也許這就是-lpthread完成的。 –

+0

我不認爲這是問題所在,代碼已經鏈接到libpthread,因爲您可以清楚地看到堆棧跟蹤顯示它正在從libpthread執行代碼:'#18 0x00007ffff64eaec6 in start_thread()from/lib64/libpthread .so.0' –

+0

@qdii:查看[libstdC++手冊](http://gcc.gnu.org/onlinedocs/libstdc++/manual/using_concurrency.html)中的要求。 – Mankarse