2014-11-19 43 views
1

我有一個C++ 11函數針對傳統C函數進行調用。我認爲創建工作線程(使用std::thread然後將變量傳遞給C函數)會很好,但是,如果線程等待執行時間太長,那麼指針不再指向內存中的有效位置。爲什麼原始指針值被覆蓋/超出範圍

例(短路爲了簡潔/可讀性,顯然不是生產代碼,但再現了問題)。

//The C function 
void c_func(const char* str1, const char* str2, const char* str3){ 

    printf("My strings str1: %s, str2: %s, str3: %s\n", str1, str2, str3); 
} 

... 

//C++ calling the function from numerous threads 
std::vector<std::thread> threads; 
std::vector<std::vector<std::string>> bar; 
... 
for (auto const& foo : bar) 
    { 
     threads.push_back(std::thread(c_func, foo[0].c_str(), foo[1].c_str(), (foo[0] + foo[1]).c_str())); 
    } 

打印輸出結果將在不同的隨機時間打印輸出的垃圾一些試驗後,我發現這確當我改變「C函數」來使用std::string而不是const char*時不會發生,但是這種改變意味着大量的重寫代碼...我寧願不這樣做...

有沒有辦法允許這種類型的多線程調用沒有指針指向垃圾如果線程沒有及時執行?或者我堅持重寫遺留代碼將其移至C++ ...

+4

你給出的指針只對'std :: string's的生命週期有效,然後歡快地繼續做你在那個線程上做的任何事情,可能會拋棄一些'std: :一路上的字符串。這基本上是打破了,沒有辦法繞過它。這與在普通數據結構中存儲'char *'沒有任何區別,刪除'string',然後從存儲它們的地方獲取'char *'。讓你的生活在一起。 – delnan 2014-11-19 19:34:42

+0

@delnan Gotcha,感謝您的意見......這是我懷疑的,但不想相信的。 – 2014-11-19 19:37:03

+2

即使沒有線程,'(foo [0] + foo [1])。c_str();'將返回垃圾,因爲臨時字符串將在完整的表達式求值後被銷燬。 – 2014-11-20 02:36:02

回答

7

因爲c_str()不會阻止清理字符串。在函數返回並清除bar之後,foo字符串也將被清理,這可能在線程啓動之前。

你應該通過實際std::string(可能是一個包裝,然後調用func之前提取char*)或以其他方式確保琴絃不會得到清理你join()編所有的線程之前。

+0

包裝的想法也出現在我的腦海裏。兩者都是最好的,不必重寫舊代碼,但仍能保證線程持續時間的指針壽命。 – 2014-11-19 19:47:40

7

這裏的線程的核心問題是父線程會在這些指針的另一端執行內存操作,使它們無效。

你需要做的是將std::string傳遞給每個線程。不是參考,不是指針,而是拷貝。現在每個線程都擁有自己的字符串副本,該副本將通過堆棧和析構函數的魔術自動清除。

現在您可以在每個字符串副本上調用c_str()以獲取對該線程有效且不在其他範圍內清理的指針。