當您構建在 Microsoft Visual C++ 6.0 應用程式使用提供標準模板庫 (STL), 記憶體損壞可能發生, 或電腦可能停止回應。 多處理器電腦上更經常發生這些癥狀。 相同代碼以前, 可能使用過沒有這樣的問題單一處理器電腦上。 當檢查錯誤線程在調試器, 通常看到記憶體管理功能中失敗。 經常看到堆疊追蹤中 basic_string < char. 按鈕 > 類方法。 由於記憶體損壞也癥狀, 方面都與字串處理無關會失敗。
堆疊追蹤屬於其中問題已是崩潰原因如下:
01 0012ebc4 77fb4014 0246ffd0 00000027 02531000 ntdll!RtlpDphReportCorruptedBlock+0x8c
02 0012ebec 77fb2cb1 02531000 01001002 0246ffd0 ntdll!RtlpDphNormalHeapFree+0x46
03 0012ec10 77fb5653 02530000 01001002 0246ffd0 ntdll!RtlpDebugPageHeapFree+0xa6
04 0012ec88 77fa760a 02530000 01001002 0246ffd0 ntdll!RtlDebugFreeHeap+0x203
05 0012ed28 77fcba9e 02530000 01001002 0246ffd0 ntdll!RtlFreeHeapSlowly+0x4d
06 0012edcc 004065a6 02530000 00000000 0246ffd0 ntdll!RtlFreeHeap+0x53
07 0012ee14 0041353a 0246ffd0 00404198 0246ffd0 main!free+0xda
08 0012ee1c 00404198 0246ffd0 0012eecc 004e9b70 main!operator delete+0x9 (FPO: [1,0,0]) (CONV: cdecl) [afxmem.cpp @ 349]
09 0012ee38 00402a71 02477fe0 00000011 004e9ce0 main!basic_string<char,char_traits_char,allocator<char> >::append_helper+0x68 (FPO: [EBP 0x0012eecc] [2,1,4]) (CONV: thiscall)
...
NTDLL! 77f97710()
NTDLL! 77fb5721()
NTDLL! 77fa760a()
NTDLL! 77fcba9e()
MSVCRT! 78001d92()
operator delete(void * 0x00c266f8) line 6 + 10 bytes
std::basic_string<char,std::char_traits<char>,std::allocator<char> >::_Tidy(std::basic_string<char,std::char_traits<char>,std::allocator<char> > * const 0x0000000f {???}, unsigned char 1) line 591 + 6 bytes
...
00 0184fb9c 60f3abc3 main!__sbh_free_block+0x173
01 0184fbb4 60f2aa93 main!free+0x28
02 0184fbbc 60f2423c main!operator delete+0x9
03 0184fce8 60f244b0 main!function(std::basic_string<char,std::char_traits<char>,std::allocator<char> > var = std::basic_string<char,std::char_traits<char>,std::allocator<char> >)+0x79c
...
...
5ed 0198de20 77fac5f4 0198dec0 0198e3f8 0198dedc ntdll!ExecuteHandler+0x26
5ee 0198dea8 77f91a96 0198dec0 0198dedc 0198dec0 ntdll!RtlDispatchException+0x76
5ef 0198df14 77b22546 2cb01468 47ac0008 00000008 ntdll!KiUserExceptionDispatcher+0xe
5f0 0198e340 1001b22c 00ed0000 00000000 00000080 ole32!SyncStubInvoke+0x61
5f1 0198e37c 1001b123 00000080 1001a4ef 00000080 main!_heap_alloc+0xed
5f2 0198e384 1001a4ef 00000080 00000001 100022f1 main!_nh_malloc+0x10 (FPO: [2,0,0])
5f3 0198e390 100022f1 00000080 0000007c 0198f430 main!operator new+0xb (FPO: [1,0,0])
5f4 0198e3b0 10002207 0000003c 0000007d 0198f42c main!std::basic_stringbuf<unsigned short,std::char_traits<unsigned short>,std::allocator<unsigned short> >::overflow+0x83 (CONV: thiscall) [C:/Program Files/Microsoft Visual Studio/VC98/INCLUDE/sstream @ 60]
5f5 0198e3cc 10003194 00000000 0000006b 0198f6e0 main!std::basic_streambuf<unsigned short,std::char_traits<unsigned short> >::xsputn+0x6a (CONV: thiscall) [C:/Program Files/Microsoft Visual Studio/VC98/INCLUDE/streambuf @ 166]
5f6 0198e404 10005621 0198f42c 010113b2 1003573c main!std::operator<<+0xb0 (CONV: cdecl) [C:/Program Files/Microsoft Visual Studio/VC98/INCLUDE/ostream @ 305]
...
原因 標準模板庫 (STL) 是以 Microsoft Visual C++ 中是不安全的多線程應用程式。 特別, std::string 類的實現依賴 basic_...
標準模板庫 (STL) 是以 Microsoft Visual C++ 中是不安全的多線程應用程式。 特別, std::string 類的實現依賴 basic_string < 按鈕 > 模板類。 basic_string < 按鈕 > 模板類引用計數隱藏字元緩衝區的副本。 在一個 8 位無符號 char basic_string < 按鈕 > 模板類儲存計數。 實現後發生下列常規問題:
不 basic_string < 按鈕 > 模板類不保護 counting 機制以所需有關線程要同時運行多處理器電腦上。 因為只有一個線程運行在時間, 和記憶體讀取或者整數上寫入完成之前可中斷其他線程單一處理器電腦上運行多線程代碼避免此問題。
寫入一個 std::string 一個線程中類可能破壞是一份 std::string 類, 如賦值, 其他線程中建立一個讀取。 supposed 副本共用同一隱藏字元緩衝區。
字串損壞可能發生指標或引用到一個 std::string 類是線程之間共用。 通常, 它負責對程式員可以避免這種情況。
必須進行線程 STL 後重建應用程式。 要擷取線程 STL 首選方法是將 STL 升級到新版本是基於當...
必須進行線程 STL 後重建應用程式。 要擷取線程 STL 首選方法是將 STL 升級到新版本是基於當前 VisualC++ 標準。 是當前 VisualC++ 標準基於 STL 但是, 不等同於 STL, Microsoft VisualC++6.0 作為新產品發行時, 無法。 但是, 升級到新版本可能會根據 STL 函數, 應用程式使用普通。 以擷取新版本的線程 STL, 使用下列方法之一:
方法 1: 使用 Microsoft Visual C++ .NET (7.0 和更高版本
在應用程式中開啟每個 VisualC++ 項目、 允許項目將自動轉換成新項目格式, 和然後重建它。 此版本中 std::string 類實現是安全執行緒對描述問題。 與重建應用程式如果您使用 DLL 執行階段程式庫功能您項目之一中應用程式, 中必須分發新 VisualC++ 執行階段程式庫組件 (如 Msvci7x.dll Msvcp7x.dll 和 Msvcr7x.dll)。
注意 您不需要分發到用戶端電腦以使用 Microsoft Visual C++ .NET Microsoft.NET 架構。
方法 2: 使用 Microsoft Visual C++ 6.0 以 STL 從第三方
細節的整合依產品, 和單個廠商提供支援。 對於後續 STL 版本一個源是 Dinkumware, Ltd., 其中 Microsoft 許可證 Visual C++ 6.0 STL 公司。 它是佔用, 它與現有構建進程整合。 有關詳細資料, 和有關的已知缺陷和變通, 列表請訪問以下 Dinkumware Web 網站:
www.dinkumware.com (http://www.dinkumware.com)
Microsoft 提供第三方聯絡資訊旨在協助您尋找支援人員。 此連絡人資訊可能更改, 恕不另行通知。 Microsoft 不保證該第三方聯絡資訊的準確性。 第三方產品, 本文討論由程式是獨立於 Microsoft 公司製造。 Microsoft 將有關效能或可靠性的這些產品沒有擔保, 暗示或其他,。
替代方法
解決 Microsoft Visual C++ 6.0 STL 中 Std::String 類問題如果執行不升級到新版的 STL, 您可以嘗試糾正 std::s...
解決 Microsoft Visual C++ 6.0 STL 中 Std::String 類問題
如果執行不升級到新版的 STL, 您可以嘗試糾正 std::string 類安全執行緒問題標準 Microsoft VisualC++6.0 安裝中。 雖然有是與幾個 Microsoft Visual C++ 6.0 STL, 中類 multi-threading 問題為止最常見和問題均為 std::string 類。 下列步驟和變通是 stopgap 措施以確保應用程式是否正常, 並且措施提供時間來調查其他方法。 考慮將這些指令建立新代碼路徑和也許整個整個應用程式行為。 徹底測試應用重建程式依照公司或個人軟體策略之前廣泛部署軟體策略之前廣泛部署。
禁用字串引用計數
每個變通本節中介紹要求您先禁用引用計數機制。 要禁用引用計數, 您必須修改 < xstring > 標頭檔, _FROZEN 枚舉常量設定為 0 。 此外預設安裝, < xstring > 標頭檔位於以下位置:
C:/ProgramFiles/Microsoft files/Microsoft Visual Studio/VC98/Include
將 _FROZEN 枚舉常數更改為 0 在行 62 頁 < xstring > 標頭檔中以便它與以下類似:
enum _Mref {_FROZEN = 0}; // set to zero to disable sharing; original value 255
如果您按照此建議, 並重建所有軟體使用這些標頭檔 std::string 類代碼將是多線程。 有一些警告到該語句。 因此, 仔細閱讀以下變通辦法說明。 禁用引用計數通過在 < xstring > 標頭檔, _FROZEN 枚舉常量設定為 0 後使用下列方法之一來解決此問題。
方法 1: 使用靜態 CRT 連結僅
在所有項目, 使用 std::string 類來連結到靜態版本的 Microsoft 執行階段程式庫 (CRT) 修改項目設定。 如果項目也有啟用 共用 DLL 中使用 MFC 設定無法使用此方法。 對於每個項目, 請按照下列步驟操作:
開啟項目。
在 項目 菜單上, 單擊 設定 。
在 配置 列表, 單擊 發布 。
" 分類 " 列表中 C/C++ 選項卡, 依次 代碼產生 。
在 執行階段程式庫 列表, 單擊 Multi-thread MT) / (
在 配置 列表, 單擊 調試 。
在 執行階段程式庫 列表, 單擊 Multi-thread 調試 (MTd) /
如果還有其他配置, 配置 列表中設定適當的 運行庫 還為這些選項。
單擊 確定 , 然後重建該項目。
此變通確保通過靜態連結到整個多線程執行階段程式庫, 包括 MFC, 所有代碼使用 < xstring > 檔案的修改版本。 一個可能問題是最終代碼大小會大於一個動態連結版本, 也許 enormously 這樣。
使用動態 CRT 連結方法 2:
如果項目代碼必須連結到運行庫 (CRT) 作為 DLL, 則必須採取其他方法。 動態 CRT 連結是預設設定對 DLL 項目。 依賴其他組件 (如 MFC 或第三方庫用於與應用程式, 授權通常需要動態連結到 CRT。 如果您只依賴是 MFC, 可使用 靜態庫中使用 MFC 選項, 並應用方法 1。 預設情況下, 在 VisualC++6.0, Microsoft 中建立新項目時項目使用 CRT 從 DLL。
動態 CRT 連結專案設定連結應用程式以對某些 std::string 類方法預置 Microsoft CRT DLL, 名為 Msvcp60.dll 中實現。 更改到 _FROZEN 常量, 您對本機複本是 < xstring > 因為通過 < xstring > 修飾標頭檔, Microsoft 內建 DLL 是不遵守對於函數調用超出該庫。 這些包括函數如 _Tidy() 和 assign() Msvcp60.DLL 檔案對於 < char > 和 < 短 > 開始的 basic_string 類中提供。 basic_string 類是基礎為 std::string 類。
要代替 Msvcp60.DLL 檔案, 中 Microsoft 提供實現模組中使用 std::string 類的靜態實現請按照下列步驟:
< xstring > 檔案, 中注釋掉附近檔案末尾發現以下代碼。 # if 0 / # endif 塊中進行此, 您可加入代碼:
#ifdef _DLL
#pragma warning(disable:4231) /* the extern before template is a non-standard extension */
extern template class _CRTIMP basic_string<char, char_traits<char>, allocator<char> >;
extern template class _CRTIMP basic_string<wchar_t, char_traits<wchar_t>, allocator<wchar_t> >;
#pragma warning(default:4231) /* restore previous warning */
#endif // _DLL
< 字串 > 標頭檔, 中定義其他字串運算子, 它們通過 Msvcp60.DLL 檔案還包括 CRT 中。 發現在結尾處有一系列 … " extern 模板 _CRTIMP " < 字串 > 檔案, 就像受 #ifdef _DLL 子句 < xstring > 檔案中定義。 注釋還出所有這些定義:
#ifdef _DLL
#pragma warning(disable:4231) /* the extern before template is a non-standard extension */
extern template class _CRTIMP
basic_string<char, char_traits<char>, allocator<char> > __cdecl operator+(
const basic_string<char, char_traits<char>, allocator<char> >&,
const basic_string<char, char_traits<char>, allocator<char> >&);
extern template class _CRTIMP
basic_string<char, char_traits<char>, allocator<char> > __cdecl operator+(
...
extern template class _CRTIMP
basic_ostream<wchar_t, char_traits<wchar_t> >& __cdecl operator<<(
basic_ostream<wchar_t, char_traits<wchar_t> >&,
const basic_string<wchar_t, char_traits<wchar_t>, allocator<wchar_t> >&);
#pragma warning(default:4231) /* restore previous warning */
#endif // _DLL
儲存對這些檔案然後再重建所有應用程式中使用 STL 項目。 如果項目聲明類 _ _ declspec (dllexport) 類 , 並且類有屬於 std::string 類型, 看到 C4251 警告。 因為所有代碼與靜態連結, 現在 std::string 類產生可忽略這些警告。 要明確禁用這些警告, 使用下列批註:
#pragma warning(disable: 4251)
此方法平衡使用 MFC 和 CRT 函數以外 std::string 類從 DLL。 沒有小代碼大小在每個模組, 使用 std::string 類中增加。
方法 3: 使用聰明駭客來避免連結問題
建立為 無符號 char 類型和使用, 而不是現有 std::string 類類型。 類型可能需要是應用程式的源檔案, 使用 std::string 類中標頭檔中包含表單。 類型可能會出現類似如下:
typedef std::basic_string<unsigned char> MyString;
#define string MyString
任何與此類使用字串必須轉換或者作為無符號字元處理。 可能存在的代碼大小與簡化的實現, 增加並且有連結少副作用。
4: 使用自訂 Std::String DLL
小代碼大小的好處通過單個 DLL 中放置 std::string 類實現該選項獲得您。 建立 DLL 項目, 匯出 std::string 類。 連結到 DLL 代替到標準 Msvcp60.DLL 檔案。 一起隨應用程式重新您必須分發此新 DLL。 這是一個進階選項。
回到頂端
更多資訊
以下 C++ 程式碼範例示範一個方案的同步不足時可能出現: ... std::string A; A = "Init"; _beginthread(Thread1...
以下 C++ 程式碼範例示範一個方案的同步不足時可能出現:
...
std::string A;
A = "Init";
_beginthread(Thread1, 0, (void*)&A);
_beginthread(Thread2, 0, (void*)&A);
A = "";
...
void Thread1(void* arg)
{
std::string A1 = *(std::string*)arg;
...
A1 = "newval";
}
void Thread2(void* arg)
{
std::string A2 = *(std::string*)arg;
...
std::string B = A2;
A2 = "newval2";
}
在本樣本, Thread1 棄置站台的輸入參數, 並引發共用字元緩衝區以 1 上引用計數。 它是使用, 時 Thread2 還棄置站台是其輸入參數, 並引發引用計數為 2時。 同時, 主線程新值分配到 A、 建立新字元緩衝區, 併除去原始共用緩衝區以 1 上引用計數。
Thread1 啟動來建立新字元緩衝區用於新指派到 A 1, 其以前共用字元緩衝區, 和然後由 1 到 0, 計數遞減上識別正引用計數。 同時, Thread2 還是過程的賦值將 B B 中共用字元緩衝區是 A2, 並嘗試之前 Thread1 0 寫入引用計數遞增為 2時它引發字元緩衝區是 A2, 上引用計數。 引用計數現代替 1 0。 如果訪問引用計數器已被同步引用計數將已經 0。
當 Thread2 將新值賦給 A2, Thread2 看到引用計數為 0 並丟棄原始共用字元緩衝區, 仍引用 B。 記憶體, 保留字元緩衝區可立即用於其他應用程式中使用。 但是, B std::string 仍將指標放到字元緩衝區。 下列情況導致損壞和故障:
B 試圖釋放字元緩衝區。
B 試圖讀取字元緩衝區的內容已被覆蓋與即時資料由其他代碼。
沒有嘗試到擴充或修改字串。