Memory leak in CWinThread!
Kalyan -- chakri@sunserv.cmc.stph.net Wednesday, October 23, 1996 Environment : Win95, VC++ 4.1 Hi all, I have created a worker thread and waiting for an event to occur. when I exit out of the application, the debug window shows the following memory leak. I was not able to fingure out what went wrong, any help would be appreciated. Thank u, Kalyan.V /* memmory leak message */ Detected memory leaks! Dumping objects -> thrdcore.cpp(156) : {78} client block at 0x006516A4, subtype 0, 104 bytes long. a CWinThread object at $006516A4, 104 bytes long {69} normal block at 0x00651248, 512 bytes long. Data: < > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD Object dump complete. The program 'C:\User Directories\Kalyan\multi\Debug\multi.exe' has exited with code 0 (0x0). /* Sample Code below */ // multiView.h : interface of the CMultiView class // //////////////////////////////////////////////////////////////////////////// #include "afxmt.h" extern CEvent g_imageIsInvalid; class CRestrictedAcess { private : CString m_data; BOOL m_flag; CRITICAL_SECTION cs; public: CRestrictedAcess() { ::InitializeCriticalSection(&cs); m_data = "Default"; m_flag = FALSE; } CRestrictedAcess(const CRestrictedAcess& right) { ::InitializeCriticalSection(&cs); ::EnterCriticalSection(&cs); m_data = right.m_data; m_flag = right.m_flag; ::LeaveCriticalSection(&cs); } CString getData() { CString data; ::EnterCriticalSection(&cs); data = m_data; ::LeaveCriticalSection(&cs); return data; } void setData(CString s) { ::EnterCriticalSection(&cs); m_data = s; ::LeaveCriticalSection(&cs); } BOOL getFlag() { BOOL flag; ::EnterCriticalSection(&cs); flag = m_flag; ::LeaveCriticalSection(&cs); return flag; } void setFlag(BOOL flag) { ::EnterCriticalSection(&cs); m_flag = flag; ::LeaveCriticalSection(&cs); } }; class CThreadSafe { public : static CRestrictedAcess m_rAcess[10]; static CWinThread *theThread; static BOOL m_waiting; static CRestrictedAcess getObject(int index) { CRestrictedAcess rAcess; CRITICAL_SECTION cs; ::InitializeCriticalSection(&cs); ::EnterCriticalSection(&cs); rAcess = m_rAcess[index]; ::LeaveCriticalSection(&cs); return rAcess; } static int findUnprocessed() { TRACE("in to find unprocessed "); for (int i = 0; i<10; i++) if (!m_rAcess[i].getFlag()) { return i; } return -1; } static UINT startProcess(LPVOID lpVoid) { while (TRUE) { int i = findUnprocessed(); Sleep(1000); if (i+1) { CRestrictedAcess temp = m_rAcess[i]; CString s; s.Format(" %d ",i); TRACE("Processing + " + temp.getData() + s + "\n"); m_rAcess[i].setFlag(TRUE); } else { AfxMessageBox("in to waiting"); TRACE("into waiting\n"); m_waiting = TRUE; ::WaitForSingleObject(g_imageIsInvalid,INFINITE); m_waiting = FALSE; TRACE("outof waiting\n"); } // end of if-else } // end of while return 0; } static void start(); }; class CMultiView : public CView { protected: // create from serialization only CMultiView(); DECLARE_DYNCREATE(CMultiView) // Attributes public: CMultiDoc* GetDocument(); // Operations public: // Overrides // ClassWizard generated virtual function overrides //{{AFX_VIRTUAL(CMultiView) public: virtual void OnDraw(CDC* pDC); // overridden to draw this view virtual BOOL PreCreateWindow(CREATESTRUCT& cs); protected: //}}AFX_VIRTUAL // Implementation public: virtual ~CMultiView(); #ifdef _DEBUG virtual void AssertValid() const; virtual void Dump(CDumpContext& dc) const; #endif protected: // Generated message map functions protected: //{{AFX_MSG(CMultiView) afx_msg void OnHelpChangeavalue(); afx_msg void OnHelpDisplayvalues(); afx_msg void OnHelpStartthread(); //}}AFX_MSG DECLARE_MESSAGE_MAP() }; #ifndef _DEBUG // debug version in multiView.cpp inline CMultiDoc* CMultiView::GetDocument() { return (CMultiDoc*)m_pDocument; } #endif ///////////////////////////////////////////////////////////////////////////// // multiView.cpp : implementation of the CMultiView class // #include "stdafx.h" #include "multi.h" #include "multiDoc.h" #include "multiView.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif CEvent g_imageIsInvalid; CWinThread *CThreadSafe::theThread = NULL; BOOL CThreadSafe::m_waiting = FALSE; CRestrictedAcess CThreadSafe::m_rAcess[10] = { CRestrictedAcess(), CRestrictedAcess(), CRestrictedAcess(), CRestrictedAcess(), CRestrictedAcess(), CRestrictedAcess(), CRestrictedAcess(), CRestrictedAcess(), CRestrictedAcess(), CRestrictedAcess() }; void CThreadSafe::start() { TRACE("Thread started\n"); theThread = AfxBeginThread((AFX_THREADPROC)CThreadSafe::startProcess,(LPVOID)0); } ///////////////////////////////////////////////////////////////////////////// // CMultiView IMPLEMENT_DYNCREATE(CMultiView, CView) BEGIN_MESSAGE_MAP(CMultiView, CView) //{{AFX_MSG_MAP(CMultiView) ON_COMMAND(ID_HELP_CHANGEAVALUE, OnHelpChangeavalue) ON_COMMAND(ID_HELP_DISPLAYVALUES, OnHelpDisplayvalues) ON_COMMAND(ID_HELP_STARTTHREAD, OnHelpStartthread) ON_COMMAND(ID_HELP_SUSPENDTHREAD, OnHelpSuspendthread) ON_COMMAND(ID_HELP_RESUMETHREAD, OnHelpResumethread) ON_COMMAND(ID_HELP_KILLTHREAD, OnHelpKillthread) //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CMultiView construction/destruction CMultiView::CMultiView() { // TODO: add construction code here } CMultiView::~CMultiView() { } BOOL CMultiView::PreCreateWindow(CREATESTRUCT& cs) { // TODO: Modify the Window class or styles here by modifying // the CREATESTRUCT cs return CView::PreCreateWindow(cs); } ///////////////////////////////////////////////////////////////////////////// // CMultiView drawing void CMultiView::OnDraw(CDC* pDC) { CMultiDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); // TODO: add draw code for native data here } //////////////////////////////////////////////////////////////////////////// // CMultiView diagnostics #ifdef _DEBUG void CMultiView::AssertValid() const { CView::AssertValid(); } void CMultiView::Dump(CDumpContext& dc) const { CView::Dump(dc); } CMultiDoc* CMultiView::GetDocument() // non-debug version is inline { ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CMultiDoc))); return (CMultiDoc*)m_pDocument; } #endif //_DEBUG ///////////////////////////////////////////////////////////////////////////// // CMultiView message handlers void CMultiView::OnHelpChangeavalue() { CThreadSafe::m_rAcess[0].setData("New"); CThreadSafe::m_rAcess[0].setFlag(FALSE); if (CThreadSafe::m_waiting) { AfxMessageBox("Waiting"); g_imageIsInvalid.SetEvent(); } } void CMultiView::OnHelpDisplayvalues() { CString s; for (int i=0; i<10; i++) { s += CThreadSafe::getObject(i).getData(); if (CThreadSafe::getObject(i).getFlag()) s += CString("TRUE") +"\n"; else s += CString("FALSE") +"\n"; } TRACE(s); } void CMultiView::OnHelpStartthread() { CThreadSafe::start(); } void CMultiView::OnHelpKillthread() { // TODO: Add your command handler code here //g_killThread.SetEvent(); // if(TerminateThread(CThreadSafe::theThread,0)) AfxMessageBox("sucessful kill"); }
Ian Pepper -- Ian@flexicom.ie Friday, October 25, 1996 [Mini-digest: 4 responses] Hi Kaylan, The memory leak is your worker thread being forcibly terminated.=20 Instead of WaitForSingleObject try using WaitForMultipleObjects with an array of two HANDLEs. The first would be as you currently have and the second, an event that signals that the app is about to terminate. If the second event is signalled then you may exit the thread procedure. Ian ian@flexicom.ie >---------- >From: Kalyan[SMTP:chakri@sunserv.cmc.stph.net] >Sent: 23 October 1996 3:58 PM >To: mfc-l@netcom.com >Subject: Memory leak in CWinThread! > >Environment : Win95, VC++ 4.1 > >Hi all, > I have created a worker thread and waiting for an event to occur. >when > I exit out of the application, the debug window shows the = following=08 > memory leak. I was not able to fingure out what went wrong, any help > would be appreciated. >Thank u, >Kalyan.V >/* memmory leak message */ > >Detected memory leaks! >Dumping objects -> >thrdcore.cpp(156) : {78} client block at 0x006516A4, subtype 0, 104 >bytes long. >a CWinThread object at $006516A4, 104 bytes long >{69} normal block at 0x00651248, 512 bytes long. > Data: < > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD >CD=20 >Object dump complete. >The program 'C:\User Directories\Kalyan\multi\Debug\multi.exe' has >exited with code 0 (0x0). > >/* Sample Code below */ > >// multiView.h : interface of the CMultiView class >// >////////////////////////////////////////////////////////////////////////= >//// >#include "afxmt.h" > >extern CEvent g_imageIsInvalid; > >class CRestrictedAcess=20 >{ >private : > CString m_data; > BOOL m_flag; > CRITICAL_SECTION cs; > =09 >public: > CRestrictedAcess() > { > ::InitializeCriticalSection(&cs); > m_data =3D "Default"; > m_flag =3D FALSE; > } > > CRestrictedAcess(const CRestrictedAcess& right) > { > ::InitializeCriticalSection(&cs); > ::EnterCriticalSection(&cs); > m_data =3D right.m_data; > m_flag =3D right.m_flag; > ::LeaveCriticalSection(&cs); > } > > CString getData() {=20 > CString data; > ::EnterCriticalSection(&cs); > data =3D m_data; > ::LeaveCriticalSection(&cs); > return data; > } > void setData(CString s) {=20 > ::EnterCriticalSection(&cs); > m_data =3D s;=09 > ::LeaveCriticalSection(&cs); > } > > BOOL getFlag() { > BOOL flag; > ::EnterCriticalSection(&cs); > flag =3D m_flag; =09 > ::LeaveCriticalSection(&cs); > return flag; =09 > } > > void setFlag(BOOL flag) { > ::EnterCriticalSection(&cs); > m_flag =3D flag; > ::LeaveCriticalSection(&cs); > } > >}; > >class CThreadSafe >{ >public : > static CRestrictedAcess m_rAcess[10]; > static CWinThread *theThread; > static BOOL m_waiting; > =09 > > static CRestrictedAcess getObject(int index) > { > CRestrictedAcess rAcess; > CRITICAL_SECTION cs; > ::InitializeCriticalSection(&cs); > ::EnterCriticalSection(&cs); > rAcess =3D m_rAcess[index]; > ::LeaveCriticalSection(&cs); > return rAcess; > } > > > static int findUnprocessed()=20 > {=09 > TRACE("in to find unprocessed "); > for (int i =3D 0; i<10; i++) > if (!m_rAcess[i].getFlag()) {=20 > return i; > } > return -1; > } > > static UINT startProcess(LPVOID lpVoid) > { > while (TRUE) { > int i =3D findUnprocessed(); > Sleep(1000); > if (i+1) > { > CRestrictedAcess temp =3D m_rAcess[i]; > CString s; s.Format(" %d ",i); > TRACE("Processing + " + temp.getData() + s + "\n");=20 > m_rAcess[i].setFlag(TRUE); > }=20 > else { > AfxMessageBox("in to waiting"); > TRACE("into waiting\n"); > m_waiting =3D TRUE; > ::WaitForSingleObject(g_imageIsInvalid,INFINITE); > m_waiting =3D FALSE; > TRACE("outof waiting\n"); > } // end of if-else > =09 > } // end of while > return 0; > } > > static void start(); > >}; > >class CMultiView : public CView >{ >protected: // create from serialization only > CMultiView(); > DECLARE_DYNCREATE(CMultiView) > >// Attributes >public: > CMultiDoc* GetDocument(); > >// Operations >public: > >// Overrides > // ClassWizard generated virtual function overrides > //{{AFX_VIRTUAL(CMultiView) > public: > virtual void OnDraw(CDC* pDC); // overridden to draw this view > virtual BOOL PreCreateWindow(CREATESTRUCT& cs); > protected: > //}}AFX_VIRTUAL > >// Implementation >public: > virtual ~CMultiView(); >#ifdef _DEBUG > virtual void AssertValid() const; > virtual void Dump(CDumpContext& dc) const; >#endif > >protected: > >// Generated message map functions >protected: > //{{AFX_MSG(CMultiView) > afx_msg void OnHelpChangeavalue(); > afx_msg void OnHelpDisplayvalues(); > afx_msg void OnHelpStartthread(); > //}}AFX_MSG > DECLARE_MESSAGE_MAP() >}; > >#ifndef _DEBUG // debug version in multiView.cpp >inline CMultiDoc* CMultiView::GetDocument() > { return (CMultiDoc*)m_pDocument; } >#endif > >////////////////////////////////////////////////////////////////////////= >///// >// multiView.cpp : implementation of the CMultiView class >// > >#include "stdafx.h" >#include "multi.h" > >#include "multiDoc.h" >#include "multiView.h" > >#ifdef _DEBUG >#define new DEBUG_NEW >#undef THIS_FILE >static char THIS_FILE[] =3D __FILE__; >#endif > > >CEvent g_imageIsInvalid; > > >CWinThread *CThreadSafe::theThread =3D NULL; >BOOL CThreadSafe::m_waiting =3D FALSE; > >CRestrictedAcess CThreadSafe::m_rAcess[10] =3D { CRestrictedAcess(), > CRestrictedAcess(), > CRestrictedAcess(), > CRestrictedAcess(), > CRestrictedAcess(), > CRestrictedAcess(), > CRestrictedAcess(), > CRestrictedAcess(), > CRestrictedAcess(), > CRestrictedAcess() }; > > >void CThreadSafe::start() >{ > TRACE("Thread started\n"); > theThread =3D >AfxBeginThread((AFX_THREADPROC)CThreadSafe::startProcess,(LPVOID)0); > >} >=09 >////////////////////////////////////////////////////////////////////////= >///// >// CMultiView > >IMPLEMENT_DYNCREATE(CMultiView, CView) > >BEGIN_MESSAGE_MAP(CMultiView, CView) > //{{AFX_MSG_MAP(CMultiView) > ON_COMMAND(ID_HELP_CHANGEAVALUE, OnHelpChangeavalue) > ON_COMMAND(ID_HELP_DISPLAYVALUES, OnHelpDisplayvalues) > ON_COMMAND(ID_HELP_STARTTHREAD, OnHelpStartthread) > ON_COMMAND(ID_HELP_SUSPENDTHREAD, OnHelpSuspendthread) > ON_COMMAND(ID_HELP_RESUMETHREAD, OnHelpResumethread) > ON_COMMAND(ID_HELP_KILLTHREAD, OnHelpKillthread) > //}}AFX_MSG_MAP >END_MESSAGE_MAP() > >////////////////////////////////////////////////////////////////////////= >///// >// CMultiView construction/destruction > >CMultiView::CMultiView() >{ > // TODO: add construction code here > >} > >CMultiView::~CMultiView() >{ >} > >BOOL CMultiView::PreCreateWindow(CREATESTRUCT& cs) >{ > // TODO: Modify the Window class or styles here by modifying > // the CREATESTRUCT cs > > return CView::PreCreateWindow(cs); >} > >////////////////////////////////////////////////////////////////////////= >///// >// CMultiView drawing > >void CMultiView::OnDraw(CDC* pDC) >{ > CMultiDoc* pDoc =3D GetDocument(); > ASSERT_VALID(pDoc); > > // TODO: add draw code for native data here >} > >////////////////////////////////////////////////////////////////////////= >//// >// CMultiView diagnostics > >#ifdef _DEBUG >void CMultiView::AssertValid() const >{ > CView::AssertValid(); >} > >void CMultiView::Dump(CDumpContext& dc) const >{ > CView::Dump(dc); >} > >CMultiDoc* CMultiView::GetDocument() // non-debug version is inline >{ > ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CMultiDoc))); > return (CMultiDoc*)m_pDocument; >} >#endif //_DEBUG > >////////////////////////////////////////////////////////////////////////= >///// >// CMultiView message handlers > >void CMultiView::OnHelpChangeavalue()=20 >{ > CThreadSafe::m_rAcess[0].setData("New"); > CThreadSafe::m_rAcess[0].setFlag(FALSE); > if (CThreadSafe::m_waiting)=20 > { > AfxMessageBox("Waiting"); > g_imageIsInvalid.SetEvent(); > } >} > >void CMultiView::OnHelpDisplayvalues()=20 >{ > CString s; > for (int i=3D0; i<10; i++) > { > s +=3D CThreadSafe::getObject(i).getData();=20 > if (CThreadSafe::getObject(i).getFlag()) s +=3D CString("TRUE") = +"\n"; > else s +=3D CString("FALSE") +"\n"; > } > TRACE(s); >} > >void CMultiView::OnHelpStartthread()=20 >{ > CThreadSafe::start(); >=09 >} > >void CMultiView::OnHelpKillthread()=20 >{ > // TODO: Add your command handler code here > //g_killThread.SetEvent(); >// if(TerminateThread(CThreadSafe::theThread,0)) >AfxMessageBox("sucessful kill"); >} > > > -----From: TedIs it just me, or do you never destroy the critical section you initialized in your constructor? Perhaps that's the source of your leak? (Off-the-cuff first guess.) -----From: Mike Blaszczak The message you get says you're leaking a CWinThread object, and it means exactly what it says. When you call AfxBeginThread(), a new object is created for you. The object isn't deleted until the thread terminates, and is only deleted automatically by MFC if the thread's m_bAutoDelete member is TRUE. You've not provided the code which shows how you shut down the thread, other than this disgusting and unacceptable hack: >// if(TerminateThread(CThreadSafe::theThread,0)) AfxMessageBox("sucessful kill"); Do not ever, ever, ever, under any circumstances, call the TerminateThread() API. It will break your application and cause you heartache. This API is wrong to use in any circumstance. You've also bogusly cast a pointer to a function in your call to AfxBeginThread: > theThread = AfxBeginThread((AFX_THREADPROC)CThreadSafe::startProcess,(LPVOID)0); This makes your thread sick and wrong from the get go. Your startProcess() function isn't shown to us, so it's impossible to tell what it's really doing. In addition, you don't show the code you use to synchronize the shutdown of the thread, so it's impossible to pinpoint your problem--but the improper management of the thread's death is the most likely cause of the problem you're experiencing. The code you've shown, though, is largely bogus and, in my estimation, the appearance of a memory leak is the least of your worries. .B ekiM http://www.nwlink.com/~mikeblas/ I'm afraid I've become some sort of speed freak. These words are my own. I do not speak on behalf of Microsoft. -----From: erik.heuer@ks-t.no (Erik Heuer) You do not call ::DeleteCriticalSection in the CRestrictedAcess destructor. -- Erik Heuer, Kongsberg Simulation & Training, 3600 Kongsberg, Norway E-mail: erik.heuer@ks-t.no Phone:(+47) 32735766 Fax:(+47) 32736965
Mike Blaszczak -- mikeblas@nwlink.com Sunday, October 27, 1996 >-----From: Ted>Is it just me, or do you never destroy the critical section you >initialized in your constructor? Perhaps that's the source of your leak? >(Off-the-cuff first guess.) >-----From: erik.heuer@ks-t.no (Erik Heuer) >You do not call ::DeleteCriticalSection in the CRestrictedAcess >destructor. These are bad conclusions. The original poster said that this diagnostic was generated by the runtime library when the application terminated: >Detected memory leaks! >Dumping objects -> >thrdcore.cpp(156) : {78} client block at 0x006516A4, subtype 0, 104 >bytes long. >a CWinThread object at $006516A4, 104 bytes long >{69} normal block at 0x00651248, 512 bytes long. > Data: < > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD >CD >Object dump complete. The message _clearly_ indicates the object which wasn't deleted is actually a CWinThread. Further, the CRITICAL_SECTION object in question is a member of the CRestrictedAcess class, not the CThreadSafe class. When a data structure (like CRITICAL_SECTION) is a member of a class, it is automatically allocated and dstroyed with the owner class. The second leak, which is 512 bytes of data of an unknown type, is allocated _before_ AfxBeginThread() is called. You can tell that because the counter for that object (69) is less than the counter for the thread object (78). If the member was a _pointer to_ a CRITICAL_SECTION, it would be possible to leak a CRITICAL_SECTION object, but that's not the case here. Even if it was happening, you'd see that the resulting dump wasn't identified as belonging to a particular object type by the runtimes. The output might look something more like: Detected memory leaks! Dumping objects -> C:\Double\Double.cpp(95) : {111} normal block at 0x00762AC0, 24 bytes long. Data: < > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD Object dump complete. Since the object isn't a CObject-derived object, the runtimes can't figure out what name its data type really has. (If you allocate a CObject-derived object, you're using MFC's CObject-specific implementation of operator new and that's what puts the class name in the preamble for the allocated memory block... in debug builds only.) The InitCriticalSection() and DeleteCriticalSection() APIs do not allocate any memory directly on behalf of your application. They let Windows know that you have a critical section, and this information is needed by the scheduler. Forgetting to delete the critical section will make the tiniest dent in Windwos performance, and you certainly shouldn't do it in a loop. But Windows cleans up everything when your process terminates and will forget your mistake at that time. This rule doesn't always apply to other synchronization objects because they can have scopes larger than the process-- that is, they can outlive a process. Forgetting to call DeleteCriticalSection() could be completely avoided by using CCriticalSection instead of using the critical section APIs directly. (Why not accept the help that MFC can offer you?) But forgetting to call DeleteCriticalSection() certainly isn't the cause of a traced memory leak in the termination of an application. .B ekiM http://www.nwlink.com/~mikeblas/ I'm afraid I've become some sort of speed freak. These words are my own. I do not speak on behalf of Microsoft.
| Вернуться в корень Архива |