2016-02-05 73 views
0

以下是較大程序的一個片段,它使用Pthreads完成。STL庫故障的列表迭代器

UpdateFunction從文本文件讀取。 FunctionMap僅用於輸出(鍵,1)。這裏基本上UpdateFunction和FunctionMap在不同的線程上運行。

queue <list<string>::iterator> mapperpool; 

void *UpdaterFunction(void* fn) { 
    std::string *x = static_cast<std::string*>(fn); 
    string filename = *x; 
    ifstream file (filename.c_str()); 
    string word; 
    list <string> letterwords[50]; 
    char alphabet = '0'; 
    bool times = true; 

    int charno=0; 

    while(file >> word) { 
     if(times) { 
      alphabet = *(word.begin()); 
      times = false; 
     } 
     if (alphabet != *(word.begin())) { 
      alphabet = *(word.begin()); 
      mapperpool.push(letterwords[charno].begin()); 
      letterwords[charno].push_back("xyzzyspoon"); 
      charno++; 
     } 
     letterwords[charno].push_back(word); 
    } 

    file.close(); 

    cout << "UPDATER DONE!!" << endl; 
    pthread_exit(NULL); 
} 

void *FunctionMap(void *i) { 
    long num = (long)i; 
    stringstream updaterword; 
    string toQ; 
    int charno = 0; 


    fprintf(stderr, "Print me %ld\n", num); 
    sleep(1); 

    while (!mapperpool.empty()) { 
     list<string>::iterator it = mapperpool.front(); 
     while(*it != "xyzzyspoon") { 
      cout << "(" << *it << ",1)" << "\n"; 
      cout << *it << "\n"; 
      it++; 
     } 
     mapperpool.pop(); 
    } 

    pthread_exit(NULL); 
} 

如果我在UpdateFunction中添加while(!mapperpool.empty()),那麼它會給我提供完美的輸出。但是當我將它移回FunctionMap時,它會在稍後給我一個奇怪的輸出和Segfaults。在UpdateFunction使用時 輸出: 打印我0 當然 帽 類 培養 類 帽 當然 當然 帽 培養 併發 .....

[每個在單獨的行中字]

當在FunctionMap中使用時輸出(片段如上所示): 打印0 更新完成! (當然%0 + 0 @ + 0 + 05P + 0cap%+ 0 + 0,05 + 0class5P?0 xyzzyspoon% + 0 + 0(+ 0%P, 0,,�0�,�05+�0����class%p,�0�,�0-�05�,�0����cap%�,�0�,�0X-�05�,�0����course%-�0 -�0�-�050-�0����course%- 0p- 0 - 05 - 0 cap% - 0 - 0H . 05 - 0 culture%. 0. 0 . 05. 0 concurrency%P. 0`. 0 . 05p. 0 (核心轉儲)

如何做到這一點?我解決了這個問題嗎?

+1

'while(* it!=「xyzzyspoon」)it ++'這非常可疑。您需要以某種方式檢查列表的結尾。誰保證列表包含指定的字符串? – bolov

+0

該列表絕對不包含該字符串。即使是這樣,我也應該至少得到正確的前幾個字符,而不是。 –

回答

1

list <string> letterwords[50]是局部對UpdaterFunction。當UpdaterFunction完成時,它的所有局部變量都被破壞了。母雞FunctionMap檢查迭代器,該迭代器已指向已刪除的內存。 插入while(!mapperpool.empty())UpdaterFunction等待FunctionMap完成,letterwords保持「活動」狀態。

1

這裏基本上UpdateFunction和FunctionMap在不同的線程運行。

而且,由於他們都處理同一對象(mapperpool)和他們都沒有使用任何pthread_mutex也不std::mutex(C++ 11),你有一個數據的比賽。如果你有數據競賽,你有未定義的行爲,程序可能會做任何想做的事情。很可能它會在整個內存中寫入垃圾直到最終崩潰,就像你看到的一樣。

我該如何解決這個問題?

通過鎖定mapperpool對象。

爲什麼列表不是線程安全的?

那麼,在絕大多數的使用情況,一個單獨的列表(或任何其他集合)將不會被多個線程使用。其餘的很大一部分鎖必須在集合上進行多於一次的操作,因此客戶將不得不自行鎖定。在鎖定操作本身有幫助的情況下,剩下的很小一部分情況不值得爲每個人增加開銷; C++的關鍵設計原則是,你只需支付你使用的東西。

藏品只有折返,這意味着在並行使用不同情況下是安全的。在並行線程

注意C++ 11引入threading library與語言很好地結合。最值得注意的是,它通過std::lock_guard,std::unique_lockstd::shared_lock(用於讀寫器鎖定)使用RAII鎖定std::mutex。一致地使用這些可以消除大量的鎖定錯誤,否則需要花費大量的時間進行調試。

如果您還不能使用C++ 11(在桌面上可以,但某些嵌入式平臺尚未得到編譯器更新),您應該首先考慮Boost.Thread,因爲它具有相同的優點。

如果你甚至不能使用,仍然嘗試尋找或寫入一個簡單的包裝器,像C++ 11/Boost那樣進行鎖定。基本的包裝只是幾行,但它會爲您節省很多調試。

請注意,C++11Boost也有原子 pthreads嚴重錯過的操作庫。

+0

是一個很好的答案!謝謝!這是一個班級任務。任務的主要目標是讓學生嘗試Pthreads庫。 –