簡體   English   中英

多線程程序中的std :: string

[英]std::string in a multi-threaded program

鑒於:

1)C ++ 03標准沒有以任何方式解決線程的存在

2)C ++ 03標准由實現決定是否std::string在其復制構造函數中使用寫時復制語義

3)寫時復制語義通常導致多線程程序中的行為無法預測

我得出以下看似有爭議的結論:

您根本無法安全,可移植地在多線程程序中使用std :: string

顯然,沒有STL數據結構是線程安全的。 但是至少,例如,對於std :: vector,您可以簡單地使用互斥鎖來保護對向量的訪問。 使用使用COW的std :: string實現,如果不編輯供應商實現內部的引用計數語義,您甚至無法可靠地做到這一點。

實際示例:

在我的公司中,我們有一個多線程應用程序,該應用程序已經過全面的單元測試,並且在Valgrind中運行了無數次。 該應用程序運行了幾個月,沒有任何問題。 有一天,我在另一版本的gcc上重新編譯了該應用程序,突然之間我一直都出現隨機段錯誤。 Valgrind現在報告了std :: string復制構造函數中libstdc ++內部的無效內存訪問。

那么解決方案是什么? 好吧,當然,我可以將typestd std::vector<char>為字符串類-但是,確實很糟糕。 我也可以等待C ++ 0x,我祈禱這將需要實現者放棄COW。 或者,(顫抖),我可以使用自定義字符串類。 我個人總是反對在已有的庫可以正常工作時實現自己的類的開發人員,但是老實說,我需要一個字符串類,我可以確定它不使用COW語義。 和std :: string根本不能保證這一點。

我說得對不對那std::string根本無法可靠地在所有便攜式,多線程程序中使用? 有什么好的解決方法?

您不能在多線程程序中安全且可移植地執行任何操作。 根本沒有可移植的多線程C ++程序之類的東西,正是因為線程將C ++所說的所有內容(包括操作順序以及修改任何變量的結果)拋到了窗外。

標准中也沒有任何內容可以保證vector可以按照您所說的方式使用。 提供具有線程擴展的C ++實現是合法的,也就是說,在其中進行初始化的線程外對向量的任何使用都會導致未定義的行為。 啟動第二個線程的那一刻,您不再使用標准的C ++,並且必須向編譯器供應商尋求什么是安全的,什么不是安全的。

如果您的供應商提供了線程擴展,並且還提供了帶有COW的std :: string(因此)無法使其成為線程安全的,那么我認為暫時您的觀點是與您的供應商或線程擴展有關,而不是符合C ++標准。 例如,可以說POSIX在使用pthreads的程序中應該禁止COW字符串。

您可以通過使用單個互斥鎖來確保其安全,該互斥鎖可以在進行任何字符串突變以及復制后讀取的任何字符串時使用。 但是您可能會對該互斥體產生殘酷的爭論。

你是對的。 這將在C ++ 0x中修復。 現在,您必須依靠實現的文檔。 例如,最新的libstdc ++版本(GCC)使您可以使用字符串對象,就像沒有字符串對象與另一個緩沖區共享其緩沖區一樣。 C ++ 0x強制實現庫以保護用戶免受“隱藏共享”的影響。

鑒於該標准沒有提及內存模型,並且完全不知道線程,我想說您不能肯定地假設每個實現都不是牛,所以不能,

除此之外,如果您了解自己的工具,則大多數實現將使用非牛字符串來允許多線程。

觀察它的更正確方法是“您不能在多線程環境中安全且可移植地使用C ++”。 也不能保證其他數據結構也可以合理地表現。 否則運行時不會使您的計算機崩潰。 該標准不保證有關線程的任何內容。

因此,要對C ++中的線程執行任何操作 ,都必須依賴於實現定義的保證。 然后,您可以安全地使用std::string因為每個實現都會告訴您在線程環境中使用是否安全。

產生第二個線程的那一刻,您就失去了真正可移植性的所有希望。 std::string不比其他語言/庫“輕便”。

您可以使用STLport。 它提供非COW字符串。 它在不同平台上具有相同的行為。

本文介紹了基於STLport字符串,繩索和GNU libstdc ++實現的具有寫時復制和非寫時復制算法的STL字符串的比較。

在我工作的公司中,我有一些運行在HP-UX 11.31上使用STLport構建而沒有STLport的服務器應用程序的經驗。 該應用程序使用優化級別為O2的gcc 4.3.1進行了編譯。 因此,當我運行使用STLport構建的程序時,與不使用STLport構建的相同程序(使用gcc自己的STL庫)相比,它處理請求的速度提高了25%。

我分析了這兩個版本,發現與具有STLport的版本(1%)相比,沒有STLport的版本在pthread_mutex_unlock() (2.5%)中花費的時間要多得多。 不帶STLport的版本中的pthread_mutex_unlock()本身是從std :: string函數之一調用的。

但是,在進行性能分析后,我以這種方式將最常稱為函數的字符串分配更改為:

string_var = string_var.c_str(); // added .c_str()

沒有STLport的版本的性能有了顯着提高。

我管理字符串訪問:

  • std::string成員std::string私有
  • 為getter返回const std::string&
  • 設置員修改成員

這對我來說一直很好,並且是正確的數據隱藏。

如果要禁用COW語義,則可以強制字符串進行復制:

// instead of:
string newString = oldString;

// do this:
string newString = oldString.c_str();

如前所述,特別是如果您可以嵌入null,則應使用迭代器ctor:

string newString(oldString.begin(), oldString.end());

在MSVC中,std :: string不再是引用計數的指向容器的共享指針。 他們在每個副本構造函數和賦值運算符中按值選擇全部內容,以避免多線程問題。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM