前言
最近在写远程获取电脑屏幕得时候遇到了多线程中共享同一内存区域,这块内存区域是new动态申请得。其中发生了一些困惑得问题,貌似是在线程切换过程中delete会无法释放new得内存区域在此记录一下。
问题描述
A线程用来new内存并delete(是个循环),B线程用来访问这块内存区域(也是个循环)。在A线程new内存后准备delete这块区域时,有可能正好切换到B线程进行访问这块内存区域。然后在切换到A线程后delete没有释放掉这块内存区域。
调试器内分析
-
调试然后先断到A线程
此时new得共享内存中已经有数据了,准备delete这块内存
-
接着运行中断到B线程,然后我们继续运行会回到A线程delete处并执行完delete。
-
当执行完delete后其指向下一条指令,这时new得数据被delete成功了
-
接着反复运行会发现delete会出现无法清除new的内存得情况
随之反复运行会发生严重的内存泄漏!
问题发生原因
猜测是在频繁的线程切换使delete发生错误。
利用线程同步避免问题
利用互对象进行线程同步,防止在delete的时候切换线程。
A线程中就用如下形式
while(1)
{
WaitForSingleObject(hmutex, INFINITE); //请求互斥对象
new ; //申请内存
ReleaseMutex(hmutex); //释放互斥对象句柄
Sleep(200); //让B进程处理
ReleaseMutex(hmutex); //释放互斥对象句柄
WaitForSingleObject(hmutex, INFINITE); //请求互斥对象
delete ; //释放内存
}
B线程形式如下
while(1)
{
WaitForSingleObject(hmutex, INFINITE); //请求互斥对象
访问共享内存
ReleaseMutex(hmutex); //释放互斥对象句柄
}
(由此还可以看出互斥对象在A进程中刚开始是WaitForSingleObject(hmutex, INFINITE)请求互斥对象会递增此线程拥有的对象计数,接着ReleaseMutex(hmutex)释放会递减此线程拥有的对象计数,但是接着有调用ReleaseMutex(hmutex)释放会递减此线程拥有的对象计数,因为此时线程已经不拥有该对象了所以函数返回错误:企图释放并非呼叫方所拥有的多用户终端运行程序,但是并不影响我们程序运行。ReleaseMutex最多是线程拥有的对象计数减到0,这样我们可以实现只有当Sleep(200)的时候B线程有机会访问共享内存,从而避免B进程在还没有new内存或者刚delete内存的时候访问无效的内存产生错误。)