多线程堆内存分配问题

greentape 2000-03-30 03:46:00
多线程堆内存分配问题

int GetIdxFileName(char ***stridx)
{
int nIdxCnt = 0, c = 0;
long hfind = 0;
_finddata_t stFind;
hfind = _findfirst("d:\\myprojects\\superseeker\\superseeker\\*.idx", &stFind);
if (hfind == -1)
{
return hfind;
}
++nIdxCnt;

while (_findnext(hfind, &stFind) != -1)
{
++nIdxCnt;
}

_findclose(hfind);

*stridx = new char*[nIdxCnt];
hfind = _findfirst("d:\\myprojects\\superseeker\\superseeker\\*.idx", &stFind);
*stridx[c] = new char[128];
strcpy(*stridx[c], stFind.name);
++c;
while (_findnext(hfind, &stFind) != -1)
{
*stridx[c] = new char[128];
strcpy(*stridx[c], stFind.name);
++c;
}
_findclose(hfind);

return nIdxCnt;
}

当在主线程中调用此函数时一切正常, 可是从主线程创建的线程调用此
函数时 *stridx = new char*[nIdxCnt]; 不能达到预期的效果。
比如说 nIdxCnt = 38; *stridx = new char*[nIdxCnt];能正常返回
可是在 *stridx[4] = new char[128]时就会出非法访问错。而0,1,2,3
没有问题.
是怎么回事???

请指点, 急死了, 谢谢!!!
...全文
802 10 打赏 收藏 转发到动态 举报
写回复
用AI写文章
10 条回复
切换为时间正序
请发表友善的回复…
发表回复
kxy 2000-03-31
  • 打赏
  • 举报
回复
to : sunsetyang
1) new是分配的全局堆。:)
2)如果你分配一个字符串如何写
char * a;
a = new char*[8];
a[0] = 一个32位的指针,//可以吗?
char*型的指针,是32位的,但是指针指向的位置是char类型。
sunsetyang 2000-03-31
  • 打赏
  • 举报
回复
本来我是以为你的算符的结合次序出了问题。但是你说的在主线程中执行时是正常的,我就放弃了这个想法。按照C的结合次序,最先结合的是[],然后是*,因此(*stridx)[c]和*stridx[c]的结合顺序不一致的。*stridx[c]的结合为*(*(stridx+c)),而(*strix)[c]的结合为*((*stridx)+c).你的分配都是基于*stridx为基址的,*(stridx+c)除c为0时是正确的外,其余都是错误的。*(stridx+c)将会修改在栈空间其他变量的值。
在主线程中居然没有出错的原因。你在上面的函数中的定义下,由于高于stridx的地址空间都是未使用的,并且主线程中的栈空间较大,所以程序没有错误。访问的非法的地址空间是空余空间。而移到最上面以后,程序修改的栈空间部分属于其他变量,因此引起了程序的非法操作。
kxy 2000-03-31
  • 打赏
  • 举报
回复
很久没有用C了。
*stridx = new char*[nIdxCnt]; //这里没有改,是正确的语句
不错,是我说错了 (我以为是 new char[nidxCnt]);
>>>(*stridx)[c] = new char[128]; //这里改正了, 由 *stridx[c] =
(*stridx)[c]表示的是 指针数组,而*stridx[c]是一个数组指针,它们
是不一样的。


greentape 2000-03-31
  • 打赏
  • 举报
回复
继续说,这个问题与线程应该一点没关系 实在报谦
原来说能在主线程中正确调用,是这样的

LRESULT CALLBACK Box (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId;
// int nType;
wmId = LOWORD(wParam);
g_hDlg = hDlg;
char szEn[128];
char szDn[128];
...
...
case IDC_BUT_TEST:
char **stridx;
GetIdxFileName(&stridx);
...
...

这样的确没有问题,很正常的样子, 但是如果把
声明stridx的地方变一变..

LRESULT CALLBACK Box (HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
char **stridx; //放到这里
int wmId;
// int nType;
wmId = LOWORD(wParam);
g_hDlg = hDlg;
char szEn[128];
char szDn[128];
...
...
case IDC_BUT_TEST:
//char **stridx;
GetIdxFileName(&stridx);
...
...

就会出那样的错了... 这是后来发现的。
在被调函数里加了那些括号后,就没有问题了。

那么,在这两个地方声明的变量有什么不一样呢?
greentape 2000-03-31
  • 打赏
  • 举报
回复
十分谢谢各位同学!!!
现在到是弄好了,是这样改了一下
int GetIdxFileName(char ***stridx)
{

int nIdxCnt = 0, c = 0;
long hfind = 0;
_finddata_t stFind;
hfind = _findfirst("d:\\myprojects\\superseeker\\superseeker\\*.idx", &stFind);
if (hfind == -1)
{
return hfind;
}
++nIdxCnt;

while (_findnext(hfind, &stFind) != -1)
{
++nIdxCnt;
}

_findclose(hfind);

*stridx = new char*[nIdxCnt]; //这里没有改,是正确的语句
ZeroMemory(*stridx, 156);
hfind = _findfirst("d:\\myprojects\\superseeker\\superseeker\\*.idx", &stFind);
(*stridx)[c] = new char[128]; //这里改正了, 由 *stridx[c] = ...
//变为(*stridx)[c] = ...
//下面也都做了这样的改变
//这样,函数在单/多线程调用中都可正常运行
//还记得么,我说过原来在主线程调用中能正
//常运行.. 我到后面去写...

strcpy((*stridx)[c], "d:\\myprojects\\superseeker\\superseeker\\");
strcat((*stridx)[c], stFind.name);

++c;
while (_findnext(hfind, &stFind) != -1)
{
(*stridx)[c] = new char[128];
strcpy((*stridx)[c], "d:\\myprojects\\superseeker\\superseeker\\");
strcat((*stridx)[c], stFind.name);
++c;
}
_findclose(hfind);
return nIdxCnt;
}

/*其实,能不能正确运行上面的程序与单/多线程全无关系。
先看一下调用函数吧
int SeekerEncryptIdxData()
{
char **stridx;
char szDest[128];
char szTitle[128];

int nIdxCnt = 0, c = 0;
nIdxCnt = GetIdxFileName(&stridx);
for (c = 0; c < nIdxCnt; c++)
{
GetFileTitle(stridx[c], szTitle);
strcpy(szDest, ENCRYPTEDDIR);
strcat(szDest, "\\");
strcat(szDest, szTitle);
SeekerEncryptTxtData(stridx[c], szDest);
ZeroMemory(szTitle, 128);
ZeroMemory(szDest, 128);
}
delete stridx; //这个delete能彻底把stridx清除吗?
return 0;
}
指针的确是容易把人弄晕的东西,。
在这里我为什么要用 char **stridx呢?
因为我调用函数需要一个字符串数组,而在掉用函数里又不能确定
数组的大小,所以不能处示化。 那么需要的数组就要在被凋函数
中初始化/创建。
被调函数这样声名int GetIdxFileName(char ***stridx); 之所以要
***是为了把指针自己的地址传进去,在这个地址上记录new 出的
堆内存的首地址, 在被调函数返回后在能确保在调用函数中使用。
我以前犯过这样的错误。例:

void FnMaster()
{
BYTE *bufmaster;
fn2(buf);
delete bufmaster; //错!
}

void FnSlave(BYTE *bufslave)
{
bufslave = new BYTE[100];
}

new 把申请的堆内存的首地址存入被new的指针变量
BYTE *buf = new buf[1];
假设 buf自己的地址为 0x0001, 申请的堆的地址为 0x1111
那么这个0x1111就记录到 0x0001的位置上,位于0x0001的
buf就有了0x1111的值即buf指向0x1111

在FnMaster调用FnSlave时 FnSlave接受的是bufmaster的值,
这本身就是不对了因为bufmaster没有初始化。
FnSlave中创建的堆地址并没有写到bufmaster, 所以返回后
的bufmaster跟本就是不可用的。

如果坚持用这种模式的话应该这样改写 FnSlave
void FnSlave(BYTE **bufslave)
{
*bufslave = new BYTE[100];
}
在调用时应该按地址

FnSlave(&bufmaster);
就可以了。 所以上面那个函数就是按这样的想法写成的,只不
过它操作的是数组的数组。

太罗嗦了.. 希望对碰到过类似问题的同学有点帮助...
sunsetyang 2000-03-31
  • 打赏
  • 举报
回复
char *a=new char[8];这样时才能进行你的操作。你上面的语句通不过编译器的,除非你进行强制类型转换。要写作:char **a=new char*[8];然后才可能通过编译器的编译。 new的操作返回的就是new操作生成对象的指针。由于a为指向char型的指针,a是一个32位的指针;a[0]不是一个32位的指针,而是一个存储空间。只有你把a定义为char **时,a[0]才是一个指向字符类型的指针,这时的存储单位是32位长度的。new的实现上本身就是调用malloc那种例程,省去了用户自己的size计算。一般的实现就是:p=new XX[size];<=>p=(XX*)malloc(sizeof(XX)*size).他的分配中使用的是new char*[c];所分配的每个域单位长度是sizeof(char*)即为32位的空间。再说,即使分配错误了,也不可能在*size[4]的时候出问题的。他分配了38单位,按照你的说法,在4的时候才用到16的地方,不可能出越界错误的。欢迎交流!!:-)
不太清楚他的问题的来源,唯一的来源可能是在主线程中也有堆的分配的调用。也只是猜的,还是请他把所有的程序都贴出来让我们看一下吧!
sunsetyang 2000-03-30
  • 打赏
  • 举报
回复
他的分配是正确的,他分配的是char*型的指针,是32位的,使用new操作分配的空间都是在进程空间内的堆空间中,并不是在栈上分配的。你的访问错误试错在*stridx[4]=new char[128] 还是下一句的地方?
kxy 2000-03-30
  • 打赏
  • 举报
回复
*stridx[c] = new char[128];//这里 *stridx[c]存放的是指针。
指针是32位。
而你在上面 *stridx = new char*[nIdxCnt];//内寸分配少了。
至于主线程中调用此函数时一切正常,是偶然现象。
Thread的堆站要小的多,所以会非法。
greentape 2000-03-30
  • 打赏
  • 举报
回复
应该不是同步的问题, 程序除主线程外只有一个子线程,在子线程生命期
中只有一次对该函数的调用。主线程没有调用。我只是在测试的时候才在
主线程中调用它。

还请继续指点啊!!!
Jackzhu 2000-03-30
  • 打赏
  • 举报
回复
要用信号同步一下,防止线程同时调用此函数,简单的用static变量标示一下,防止同时访问本函数

15,472

社区成员

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

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