问题由来: 一个多线程程序运行一段时间后变得不正常,许多string类型变量的内容不正常。
因为程序在本机运行一直正常,而拿到一台服务器上运行有问题,怀疑服务器上是多CPU具有
真正的并发性造成某个未同步的变量操作异常。检查所有应该同步的代码,似乎都进行了正确的同步。
大致代码如下:
#include "stdafx.h"
#include <process.h>
#include <iostream>
#include <conio.h>
#include <string>

string g_str;
CRITICAL_SECTION g_cs;


void LockString()
{ EnterCriticalSection(&g_cs); };

void UnlockString()
{ LeaveCriticalSection(&g_cs); };

void SetString(char * szText)


{
LockString();

g_str = szText;

UnlockString();
}

string GetString()


{
string strResult;

LockString();

strResult = g_str;

UnlockString();

return strResult;
}

UINT ThreadProc(LPVOID lpParam)


{
// 为了使现象明显,这里进行了大量循环
for(int i = 0; i < 200000; i++)

{
string strTmp = GetString();
}

return 0;
}

#define MAX_THREADS 200

int main(void)


{
::InitializeCriticalSection(&g_cs);

SetString("VC知识库");

HANDLE hThreads[MAX_THREADS];

UINT nThreadID;
int i;

// 开启线程
for(i = 0; i < MAX_THREADS; i++)
hThreads[i] = (HANDLE)_beginthreadex(NULL, 0, (unsigned (__stdcall *)(void *))ThreadProc, NULL, 0, &nThreadID);

// 等待线程结束
for(i = 0; i < MAX_THREADS; i++)
::WaitForSingleObject(hThreads[i], INFINITE);
// 输出结果
cout << "string:" << GetString() << endl;

::DeleteCriticalSection(&g_cs);

getch();
return 0;
}
代码中唯一共用的变量g_str已经用临界区进行了同步,似乎没有问题了。但运行的时候却发现有时没有运行到cout时程序便异常退出,
或cout并没有输出正确的字符串。
经过调试最后发现问题是出在 string strTmp = GetString();
因为VC6自带的STL中的string采用cow方式,这种字符串的浅拷贝带来了多线程时的安全问题。而且这种错误隐藏得比较深,很难调试排错。
结论:如果要在多线程程序中进行string变量的传递,建议使用深拷贝的string类,听说stlport没问题(本人没有测试过),如果采用VC.NET, 其自带的string是安全的。
测试环境:双Intel Xeon CPU 2.8G, WIN2003, VC6, VC.NET
posted on 2005-07-01 22:19 王骏的BLOG 阅读(3976)
评论(21) 编辑 收藏