因为程序在本机运行一直正常,而拿到一台服务器上运行有问题,怀疑服务器上是多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类。
标准库里面的string在多线程下并不保证是都是安全的,只提供两种安全机制:
1.多个线程同时读取数据是安全的。
2.只有一个线程在写数据是安全的。