多线程使用STL中的map时出现异常。。。

templarzq 2008-12-12 09:55:02
代码如下:



#ifdef _WIN32
#pragma warning(disable: 4786 4251)
#endif

#include <time.h>
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <map>
#include <string>

#define THREADNUM 10
#define MSG_START WM_USER+101

using namespace std;

DWORD WINAPI proc(LPVOID lparam);

class _param
{
public:
map<int,map<int ,string > > test;
};
/* struct _param
{
map<int,map<int ,string > > test;
};
*/
class A
{
public:
string a;
// struct _param *b;
_param *b;
};
class B
{
public:
map<int,class A> a;
};

int main(int argc, char* argv[])
{
HANDLE hThread[THREADNUM];
DWORD threadid[THREADNUM];
time_t curtime;
//struct _param * param;
//param=new struct _param ;
_param * param;
param=new _param ;
map<int,string> tmpmap;
tmpmap.insert(pair<int,string> (1,"aa"));
tmpmap.insert(pair<int,string> (2,"bb"));
param->test.insert(pair<int,map<int,string> > (1,tmpmap));
tmpmap.insert(pair<int,string> (3,"cc"));
param->test.insert(pair<int,map<int,string> > (2,tmpmap));

A aa;
aa.b=param;
aa.a="nn";
B bb;
bb.a.insert(pair<int,A> (1,aa));
bb.a.insert(pair<int,A> (2,aa));

int i;
for( i=0;i<THREADNUM;i++)
{
hThread[i]=CreateThread(NULL,0,proc,&bb,0,threadid+i);
}
Sleep(2000);
for(i=0;i<THREADNUM;i++)
{
PostThreadMessage(threadid[i],MSG_START,0,0);
}

curtime=time(NULL);
printf("curtime=%d\n",curtime);
WaitForMultipleObjects(THREADNUM,hThread,true,INFINITE);
curtime=time(NULL);
printf("curtime=%d\n",curtime);
return 0;
}

DWORD WINAPI proc(LPVOID lparam)
{
B *param=(B*)lparam;
map<int,string> ::iterator tmpiter;
map<int,A > ::iterator iter;
MSG strumsg;
map<int ,A> con;
A *cc;
while(1)
{
int ret=GetMessage(&strumsg,NULL,MSG_START,MSG_START);
if(ret==0)
{
return 0;
}
else
{
for(int i=0;i<10000000000;i++)
{
con=param->a;
cc=new A;
/* for(iter=param->a.begin();iter!=param->a.end();iter++)
{
*cc=iter->second;
//cc->a="cc";
con.insert(pair<int,A> (1,*cc));
}
*/ delete cc;

printf("end. \n");
if(i%50000==0)
printf("%d\n",i);
}
return 0;
}
}

return 0;
}


工程编译参数:

/nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /Fo"Debug/" /Fd"Debug/" /FD /LDd /GZ /c

异常如下:

HEAP[tesmulitthreadmap.exe]: HEAP: Free Heap block 3b4f38 modified at 3b4f60 after it was freed
运行环境为:
双核E4600,2G内存。

单核cpu运行时不会出现异常。
请大家分析下原因。。。。
分不够可以再加。
...全文
933 36 打赏 收藏 转发到动态 举报
写回复
用AI写文章
36 条回复
切换为时间正序
请发表友善的回复…
发表回复
DDGG 2009-01-20
  • 打赏
  • 举报
回复
[Quote=引用 30 楼 templarzq 的回复:]
bug.....

vc6的stl库中map底层的红黑树(文件名xtree)实现里有这么个玩意:

C/C++ codeprotected:
static _Nodeptr _Nil;
static size_t _Nilrefs;



而它在修改这些变量的时候居然用局部对象加锁。。。太可笑了,那玩意能锁得住吗??

C/C++ code void _Init()
{_Nodeptr _Tmp = _Buynode(0, _Black);
{_Lockit _Lk;

[/Quote]

我想_Lockit _Lk;定义的局部变量应该是利用了对象的析构函数来解锁,在变量定义的时候加锁,变量超出生存期的时候就自动解锁了。
参考这篇文章:http://www.xfbbs.com/ArticleShow/130/Article_Show_21479.html
yamiky 2009-01-14
  • 打赏
  • 举报
回复
代码本身没多大问题,唯一的问题是不要用CreateThread,而应该改用_beginthreadex,因为后者会对线程C运行库的必要环境进行初始化,其中就包括多线程的处理,这点很重要,还有VC6所自带的那个STL版本,本身就不是线程安全的,建议改用STLPORT或者改用VC2005
sealy_2007 2008-12-21
  • 打赏
  • 举报
回复
for(int i=0;i<10000000000;i++)
{
con=param->a;
cc=new A;
/* for(iter=param->a.begin();iter!=param->a.end();iter++)
{
*cc=iter->second;
//cc->a="cc";
con.insert(pair<int,A> (1,*cc));
}
*/ delete cc;

printf("end. \n");
if(i%50000==0)
printf("%d\n",i);
}

这段里面你注释的代码有没有执行过?这段代码如果执行,con绝对会有线程安全问题,尝试这样用也不是好习惯;
你的错误如果是内存被delete以后还被修改,可以用微软的AppVerify跑一下,这个工具可以马上查到是谁在使用被delete的内存
luobonic 2008-12-21
  • 打赏
  • 举报
回复
mian里
_param * param;
param=new _param ;
改写为_param xobject;_param* param=&xobject;
C_MFC 2008-12-12
  • 打赏
  • 举报
回复
用EnterCriticalSection(&cs); LeaveCriticalSection(&cs); 同步一下!没有同步!
templarzq 2008-12-12
  • 打赏
  • 举报
回复
不好意思,那个数确实大点了,可以删掉几个0。。。我是用VC6sp6跑的。编译参数上边也有。
cnzdgs 2008-12-12
  • 打赏
  • 举报
回复
你的代码没什么问题,各个线程对共享数据都是只读,不会有冲突。可能是系统环境有问题或者是遇到了编译器的bug,你的VC是哪个版本?
在我的电脑上运行你这段代码有半个小时了,还出错,我的CPU是E6550。

(顺便提一下,10000000000已经超过了32位整数的表示范围。)
templarzq 2008-12-12
  • 打赏
  • 举报
回复
迭代器唯一????爆汗啊。。。。。。
每种类型的迭代器都是唯一的??
难道迭代器没有对象这个概念吗?
不可以生成多个对象?
zhoujianhei 2008-12-12
  • 打赏
  • 举报
回复
STL的迭代器是唯一的,而且是非线程安全的,当多个线程运行到
con=param->a; 时,它们使用同一个迭代器进行遍历a的元素取值并添加到con中。
单核不出错的原因,可能是顺序执行的,也就是说,一旦线程进入
for(int i=0;i<10000000000;i++)
{
...
}
就没机会切出去,致使几个线程顺序执行。多核则不同。

ltps123 2008-12-12
  • 打赏
  • 举报
回复
跟单核没关系啊,你的param->a多次释放了,你的每个线程里面都有他的指针,如果把屏蔽的那段开开,那肯定是会多次释放的.
后面的A,B类都是多次指向同一个param对象,释放会多次释放的,该把线程同步加上,再判断数据存在,释放
templarzq 2008-12-12
  • 打赏
  • 举报
回复
而且邪门的是我实际调用的时候是dll里一个函数进行拷贝操作,加了semaphore这种内核变量都无济于事,照样出异常。
但如果拉到线程里直接加同步锁就没事。。。。
templarzq 2008-12-12
  • 打赏
  • 举报
回复
怎么会数据不对呢。。。。。。又没有释放,没有写入操作。。。
oyljerry 2008-12-12
  • 打赏
  • 举报
回复
[Quote=引用 13 楼 templarzq 的回复:]
呵呵,不用怀疑,就是它出问题啦。我觉得奇怪的是我只是做一个拷贝,为什么要加临界区?又没有对公共对象做写入操作。。。。
[/Quote]
刚好访问的时候param, 或param->a数据不对了等可能
templarzq 2008-12-12
  • 打赏
  • 举报
回复
呵呵,不用怀疑,就是它出问题啦。我觉得奇怪的是我只是做一个拷贝,为什么要加临界区?又没有对公共对象做写入操作。。。。
zhoujianhei 2008-12-12
  • 打赏
  • 举报
回复
也不是很确定,不过con=param->a; 最值得怀疑,你最好还是测试一下。

zhoujianhei 2008-12-12
  • 打赏
  • 举报
回复
class B
{
B() { InitializeCriticalSection(&cs); }
~B() { DeleteCriticalSection(&cs); }

public:
void Lock() { EnterCriticalSection(&cs); }
void Unlock() { LeaveCriticalSection(&cs); }

public:
map<int,class A> a;
CRITICAL_SECTION cs;

};

param->Lock();
con=param->a;
param->Unlock();

caitian6 2008-12-12
  • 打赏
  • 举报
回复
关注
templarzq 2008-12-12
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 zhoujianhei 的回复:]

con=param->a;
进行同步,测试一下。
[/Quote]
我在实际使用的时候是在dll模块中循环拷贝,怎么在dll中加锁?
Conry 2008-12-12
  • 打赏
  • 举报
回复
多线程用一个资源肯定要同步的
zhoujianhei 2008-12-12
  • 打赏
  • 举报
回复

con=param->a;
进行同步,测试一下。

加载更多回复(16)

15,471

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 进程/线程/DLL
社区管理员
  • 进程/线程/DLL社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧