跨线程delete操作为什么会失败?

zyq1600356618 2009-09-10 11:37:24
跨线程delete操作为什么会失败?

而且只在debug下才报错,release又是好的

调试的时候弹出 终止,重试,忽略 的对话框

我知道线程都有自己的堆,难道就不能删别人堆上的东西吗? 就算不能,那为什么release下又不报错?

我的程序要求一个线程A产生(new)字符串数据,并把指针传递到另一个线程B,线程B处理完后删除(delete),删除的时候就出错了...
怎么解决啊???
...全文
778 31 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
31 条回复
切换为时间正序
请发表友善的回复…
发表回复
intotheroom 2010-09-28
  • 打赏
  • 举报
回复
学习中啊...
xge 2009-09-11
  • 打赏
  • 举报
回复
follow 16楼的建议, 看一看两个DLL的编译选项,都动态连接CRT应该就没事了。
dong364 2009-09-11
  • 打赏
  • 举报
回复
线程B要确保有消息队列,可通过msdn查找怎样确保。线程B接受的消息参数应该判断是否为WM_USER+130,你能确保debug下线程B只接受WM_USER+130吗?
zyq1600356618 2009-09-11
  • 打赏
  • 举报
回复
[Quote=引用 21 楼 dong364 的回复:]
引用 5 楼 zyq1600356618 的回复:
线程A的代码:
C/C++ codeTCHAR* text=new TCHAR[10];
::PostThreadMessage(g_ThreadID_A,WM_USER+130,0,(LPARAM)text);


线程B的代码:
C/C++ codeTCHAR* p_ch=(TCHAR*)msg.lParam;
delete []p_ch;

问题:
1. 几个进程?
2. 线程A向自己发消息?用PostThreadMessag, lz查过PostThreadMessage用法吗?
3. 误导“堆”与“堆栈”概念。
[/Quote]
1->1个进程,3个线程,3个模块,每个模块各自一个线程,没有窗口.
2->这里是我发帖的笔误,应该是g_ThreadID_B.
3->这个就不懂了...

我的消息的确是发送到B了,调试跟踪发现参数也都一样(text和p_ch),B也没收到其他消息
#18楼的说法虽然与解决这个问题无关,但也很有用,谢谢了^.^

dong364 2009-09-11
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 zyq1600356618 的回复:]
线程A的代码:
C/C++ codeTCHAR* text=new TCHAR[10];
::PostThreadMessage(g_ThreadID_A,WM_USER+130,0,(LPARAM)text);


线程B的代码:
C/C++ codeTCHAR* p_ch=(TCHAR*)msg.lParam;
delete []p_ch;
[/Quote]
问题:
1. 几个进程?
2. 线程A向自己发消息?用PostThreadMessag, lz查过PostThreadMessage用法吗?
3. 误导“堆”与“堆栈”概念。
skywoodsky 2009-09-11
  • 打赏
  • 举报
回复
如果要跨模块(dll)删,那exe和dll的编译模式要对应
即exe是debug的话,dll也要是debug的,不然就会错
rendao0563 2009-09-11
  • 打赏
  • 举报
回复
[Quote=引用 15 楼 zyq1600356618 的回复:]
引用 14 楼 rendao0563 的回复:
是同一个模块吗。有用dll之类的吗。

是两个不同的dll,加一个exe调用这两个dll,3个模块...
[/Quote]

你所谓的release不报错。只是说明这个问题还没有导致崩溃而已。
在A模块分配的内存必须由A模块的代码负责释放。举个例子吧。

如果你在A模块 CPlayer *pPlayer = new CPlayer; //分配了一个对象
而在B模块你要删除 delete pPlayer; //那是肯定会出错的。

正确的做法是CPlayer提供一个释放接口如:Release();
在B调用pPlayer->Release();就可以了。Release的实现其实就是个 delete this;

如果你只是使用普通的数据结构,并且你需要释放别的模块提供的堆数据,你让数据提供模块提供一个释放接口给你就可以了比如:
void MyDelete(char *pHeap)
{
delete pHeap;
}
//要导出

重点不是线程是模块,产生的原因是 windows堆是按模块划分的。所有的内存分配最后都会调用HeapAlloc.而释放都会调用HeapFree. 而他们的第一个参数都是模块堆句柄。也就是如果你在B中调用delete pPlayer;导致的结果就是HeapFree(B模块堆句柄,...);而不是他真正需要的HeapFree(A模块堆句柄,...);
这说明new最终调用HeapAlloc(取当前模块堆句柄,...); 是这么用的。

无代码无真相,贴代码。



#ifdef _WIN64
return HeapAlloc(_crtheap, 0, size ? size : 1);
#else /* _WIN64 */
if (__active_heap == __SYSTEM_HEAP) {
return HeapAlloc(_crtheap, 0, size ? size : 1);
} else
if ( __active_heap == __V6_HEAP ) {
if (pvReturn = V6_HeapAlloc(size)) {
return pvReturn;
}
}
#ifdef CRTDLL
else if ( __active_heap == __V5_HEAP )
{
if (pvReturn = V5_HeapAlloc(size)) {
return pvReturn;
}
}
#endif /* CRTDLL */


其中HANDLE _crtheap=NULL; 代码在heapinit.c中。_crtheap最终会被设定为当前模块堆句柄。
代码如下:

if ( (_crtheap = HeapCreate( mtflag ? 0 : HEAP_NO_SERIALIZE,
BYTES_PER_PAGE, 0 )) == NULL )
return 0;



intptr_t __cdecl _get_heap_handle(void)
{
_ASSERTE(_crtheap);
return (intptr_t)_crtheap;
}


如果需要你是可以建立一个自己独立使用的堆的。
hlq83 2009-09-11
  • 打赏
  • 举报
回复
或者你的dll,exe都用同一个运行库,估计问题也不大。
hlq83 2009-09-11
  • 打赏
  • 举报
回复
我觉得跟线程没关系,new和delete最好在同一个dll做,你可以在new的那个dll输出一个delete那块内存的输出函数。然后在delete的地方调用这个函数,应该不会出问题。
zyq1600356618 2009-09-11
  • 打赏
  • 举报
回复
这样之后所有的模块都是用的同一个堆,内存管理要方便的多^.^
zyq1600356618 2009-09-11
  • 打赏
  • 举报
回复
[Quote=引用 25 楼 rendao0563 的回复:]
被无视了。
[/Quote]
呵呵,不好意思啊
你说的也在理,自己管理一个堆就没这个问题,但是会使程序更麻烦,
我也试过像MFC里的那样重载new和delete操作,差不多都能解决,但也很麻烦

[Quote=引用 24 楼 xge 的回复:]
follow 16楼的建议, 看一看两个DLL的编译选项,都动态连接CRT应该就没事了。
[/Quote]
还得多谢xge的关于CRT的提醒,把运行时库调成/MDd(debug版)和/MD(release版)就可以了
zyq5945 2009-09-11
  • 打赏
  • 举报
回复
没有问题的啊
#include <stdio.h>
#include <windows.h>
#include <iostream.h>
#include <process.h>

#define UM_MSG1 WM_USER+1
#define UM_MSG2 WM_USER+2

DWORD WINAPI Thread1(LPVOID para)
{

DWORD dwThreadId = *(DWORD *)para;
DWORD i=0;
TCHAR *p;
char strTmp[100];

while(TRUE)
{
Sleep(1700);
p=new TCHAR[10];
sprintf(strTmp,"Hello %d %x",i++,p);
PostThreadMessage(dwThreadId,UM_MSG1,(WPARAM)strTmp,(LPARAM)p);
}

return 0;

}

DWORD WINAPI Thread2(LPVOID para)
{

char strTmp[100];
DWORD dwThreadId = *(DWORD *)para;
DWORD i=0;
TCHAR *p;
while(TRUE)
{

Sleep(3000);
p=new TCHAR[10];
sprintf(strTmp,"World %d %x",i++,p);
PostThreadMessage(dwThreadId,UM_MSG2,(WPARAM)strTmp,(LPARAM)p);
}

return 0;

}

int main()
{

DWORD dwValue =GetCurrentThreadId();
HANDLE hThread1 = CreateThread(NULL,0,&Thread1,&dwValue,0,NULL);
HANDLE hThread2 = CreateThread(NULL,0,&Thread2,&dwValue,0,NULL);
CloseHandle(hThread1);
CloseHandle(hThread2);
MSG msg;
while(GetMessage(&msg,NULL,0,0))
{
switch(msg.message)
{
case UM_MSG1:
case UM_MSG2:
printf("msg:0x%x %s %x\n",msg.message,msg.wParam,msg.lParam);
delete (TCHAR *)msg.lParam; //注释掉这句你就会看到堆内存地址变化
break;
default:
printf("Unknown msg:0x%x\n",msg.message);
break;
}
//Sleep(1);
}
return 0;
}
rendao0563 2009-09-11
  • 打赏
  • 举报
回复
被无视了。
xge 2009-09-10
  • 打赏
  • 举报
回复
几个概念性的问题
线程没有自己的堆
new和delete是CRT函数
每一个CRT都有自己的堆
一个进程可能有好几个CRT
每一个new出的地址都属与new函数所属的CRT的堆, 不能再其他堆中删除。
delete会从delete函数所属的堆中删除
一个地址删两便会出错
一个地址所属的堆corrupt,删除会出错
buffer overflow, underflow 会造成buffer所属的堆corrupt.

这么多信息,应该够你分析了

zyq1600356618 2009-09-10
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 muzizongheng 的回复:]
加锁!!!!!
不然线程同步问题 会导致程序崩溃。
[/Quote]
应该不纯在同步问题吧,线程A new操作完成之后才通知线程B 要操作的地址,而且只有一次(测试),
线程A只管new,线程B也只管delete,而且线程B执行delete的时候,线程A也没退出,都有消息循环
muzizongheng 2009-09-10
  • 打赏
  • 举报
回复
加锁!!!!!

不然线程同步问题 会导致程序崩溃。
zyq1600356618 2009-09-10
  • 打赏
  • 举报
回复
[Quote=引用 4 楼 aa3000 的回复:]
(new)字符串数据 只在 B 线程使用吗?有可能在其他线程被释放了。
[/Quote]
是只在B线程使用的
zyq1600356618 2009-09-10
  • 打赏
  • 举报
回复
线程A的代码:
TCHAR* text=new TCHAR[10];
::PostThreadMessage(g_ThreadID_A,WM_USER + 130,0,(LPARAM)text);



线程B的代码:
TCHAR* p_ch=(TCHAR*)msg.lParam;
delete []p_ch;
aa3000 2009-09-10
  • 打赏
  • 举报
回复
(new)字符串数据 只在 B 线程使用吗?有可能在其他线程被释放了。
  • 打赏
  • 举报
回复
这个可能是代码写的有错误。在debug模式下局部变量别填充为0xcc 而在release模式下则不自动填充为0xcc,分配的内存内容是随机的。
所以你的代码可能是:代码中出现了指向new所分配的内存的变量出了有效的局部范围。在B进程中使用时由于出了有效的局部范围,使得指向该new所分配空间的指针变量被填充了0xcc,导致错误,而在release模式下则不填充为0xcc,值还是原来的值。所以恰好正确的访问了new所分配的内存区域。
这个错误 是由你的变量在有效范围外被引用导致的,仔细检查代码。
(个人见解)
加载更多回复(11)

15,473

社区成员

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

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