关于windows程序设计的一些问题

2017-09-13 20:34:18来源:CSDN作者:U___0人点击

分享
本人自学Windows程序设计(第三版)这本书,用以学习windows api

,(msdn看着有点费劲)。章节到第三章时,出现了一些问题,特在此整理一下。


在书中章节3.3设计自己的线程局部存储 中,作者所写的实例通过各线程共享一个CSlotThreadData对象,各线程分别新建自己的CNoTrackObject对象,使用一个m_nSlot变量通过调用CSlotThreadData对象的AllotSlot成员函数获得一个Slot槽。

但作者的代码有些问题,额,先贴源码吧。


_AFXTLS_.h文件

#ifndef _AFXTLS_H_#define _AFXTLS_H_#include<stdio.h>#include<windows.h>#include<stddef.h>#include<iostream>using namespace std;using std::cout;using std::endl;class CSimpleList{public:	CSimpleList(int nNextOffSet = 0);	void Construct(int nNextOffset);	//给用户的函数接口	bool  IsEmpty() const;	void  AddHead(void* p);	void* GetHead() const;	bool  Remove(void* p);	void  RemoveAll();	void* GetNext(void* p) const;	//需要用到的成员	void* m_pHead;	int   m_nNextOffSet;	void** GetNextPtr(void* p) const;};inline CSimpleList::CSimpleList(int nNextOffSet){	m_pHead = NULL;	m_nNextOffSet = nNextOffSet;}inline void CSimpleList::Construct(int nNextOffSet){	m_nNextOffSet = nNextOffSet;}inline bool CSimpleList::IsEmpty() const{	return m_pHead == NULL;}inline void* CSimpleList::GetHead() const{	return m_pHead;}inline void CSimpleList::RemoveAll(){	m_pHead = NULL;}inline void** CSimpleList::GetNextPtr(void* p) const{	return (void**)((BYTE*)p + m_nNextOffSet);}inline void* CSimpleList::GetNext(void* p) const{	return *GetNextPtr(p);}template<class TYPE>class CTypedSimpleList : public CSimpleList{public:	CTypedSimpleList(int nNextOffSet = 0) :CSimpleList(nNextOffSet){};	void  AddHead(TYPE p)	{		CSimpleList::AddHead((void*)p);	}	TYPE GetHead() const	{		return (TYPE)CSimpleList::GetHead();	}	bool  Remove(TYPE p)	{		return CSimpleList::Remove((void*)p);	}	TYPE  GetNext(void* p) const	{		return (TYPE)CSimpleList::GetNext(p);	}	operator TYPE()	{		return (TYPE)CSimpleList::GetHead();	}};class CNoTrackObject{public:	CNoTrackObject(){ cout << "CNoTrackObject()" << endl; }	void* operator new(size_t nSize);	void  operator delete(void* p);	virtual ~CNoTrackObject(){ cout << "~CNoTrackObject()" << endl; };};struct CSlotData;struct CThreadData;class CSlotThreadData{public:	//构造函数	CSlotThreadData();	//接口函数	int SlotAlloc();	void SlotFree(int nSlot);	void* GetThreadValue(int nSlot);	void SetThreadValue(int nSlot, void* pValue);	void DeleteValues(HINSTANCE hInst, bool bAll = false);	//成员	void DeleteValues(CThreadData* pData, HINSTANCE hInst);	void* operator new(size_t, void* p)	{		return p;	}	DWORD m_tlsIndex;	int m_nAlloc;	int m_nRover;	int m_nMax;	CSlotData* m_pSlotData;	CTypedSimpleList<CThreadData*> m_list;	CRITICAL_SECTION m_cs;	//析构函数	~CSlotThreadData();};class CThreadLocalObject{public:	CThreadLocalObject(){ cout << "CThreadLocalObject()" << endl; };	CNoTrackObject* GetData(CNoTrackObject* (*pCreateObject)());	CNoTrackObject* GetDataNA();	int m_nSlot;	~CThreadLocalObject();};template<class TYPE>class CThreadLocal :public CThreadLocalObject{public:	static CNoTrackObject* CreateObject()	{		return new TYPE;	}	TYPE* GetData()	{		return (TYPE*)CThreadLocalObject::GetData(&CreateObject);	}	TYPE* GetDataNA()	{		return (TYPE*)CThreadLocalObject::GetDataNA();	}	operator TYPE*()	{		return GetData();	}	TYPE* operator ->()	{		return GetData();	}};#endif

_AFXTLS_.cpp文件

#include "stdafx.h"#include"_AFXTLS_.h"#ifdef _AFXTLS_H_using namespace std;using std::cout;using std::endl;void CSimpleList::AddHead(void* p){	*GetNextPtr(p) = m_pHead;	m_pHead = p;}bool CSimpleList::Remove(void* p){	//如果p为空 结束函数 	if (p == NULL)		return false;	bool bRet = false;//先假定删除失败	if (p == m_pHead)	{		m_pHead = GetNext(p);	}	else	{		void* pTest = m_pHead;		while (pTest != NULL && p != GetNext(pTest))		{			pTest = GetNext(pTest);		}		if (pTest == NULL)		{			printf("pTest == NULL/n");			return bRet;		}		*GetNextPtr(pTest) = GetNext(p);	}	bRet = true;	return bRet;}void* CNoTrackObject::operator new(size_t nSize){	void* p = ::GlobalAlloc(GPTR, nSize);	return p;}void CNoTrackObject::operator delete(void* p){	if (p != NULL)	{		::GlobalFree(p);	}}struct CSlotData{	DWORD dwFlags;	HINSTANCE hInst;};struct CThreadData :public CNoTrackObject{	CThreadData* pNext;	int nCount;	LPVOID* pData;};#define SLOT_USED 0x01CSlotThreadData::CSlotThreadData(){	cout << "CSlotThreadData()" << endl;	m_tlsIndex = ::TlsAlloc();	m_list.Construct(offsetof(CThreadData, pNext));	m_nAlloc = 0;	m_nMax = 0;	m_nRover = 1;	m_pSlotData = NULL;	::InitializeCriticalSection(&m_cs);}int CSlotThreadData::SlotAlloc(){	::EnterCriticalSection(&m_cs);	int nAlloc = m_nAlloc;	int nSlot = m_nRover;	if (nSlot >= nAlloc || m_pSlotData[nSlot].dwFlags & SLOT_USED)	{		for (nSlot = 1; nSlot<nAlloc && m_pSlotData[nSlot].dwFlags&SLOT_USED; nSlot++);		if (nSlot >= nAlloc)		{			int nNewAlloc = nAlloc + 32;			HGLOBAL p;			if (m_pSlotData == NULL)			{				p = ::GlobalAlloc(GMEM_MOVEABLE, sizeof(CSlotData)*nNewAlloc);			}			else			{				p = ::GlobalHandle(m_pSlotData);				::GlobalUnlock(p);				p = ::GlobalReAlloc(p, sizeof(CSlotData)*nNewAlloc, GMEM_MOVEABLE);			}			CSlotData* pData = (CSlotData*)::GlobalLock(p);			memset(pData + nAlloc, 0, (nNewAlloc - nAlloc)*sizeof(CSlotData));			m_pSlotData = pData;			m_nAlloc = nNewAlloc;		}	}	if (nSlot >= m_nMax)	{		m_nMax = nSlot + 1;	}	m_pSlotData[nSlot].dwFlags |= SLOT_USED;	m_nRover = nSlot + 1;	::LeaveCriticalSection(&m_cs);	return nSlot;}void CSlotThreadData::SetThreadValue(int nSlot, void* pValue){	CThreadData* pData = (CThreadData*)::TlsGetValue(m_tlsIndex);	if ((pData == NULL || pData->nCount <= nSlot) && pValue != NULL)	{		if (pData == NULL)		{			pData = new CThreadData;			pData->nCount = 0;			pData->pData = NULL;			::EnterCriticalSection(&m_cs);			m_list.AddHead(pData);			::LeaveCriticalSection(&m_cs);		}		if (pData->pData == NULL)		{			pData->pData = (void**)::LocalAlloc(LMEM_FIXED, sizeof(LPVOID)*m_nMax);		}		else		{			pData->pData = (void**)::LocalReAlloc(pData->pData, sizeof(LPVOID)*m_nMax, LMEM_MOVEABLE);		}		memset(pData->pData + pData->nCount, 0, sizeof(LPVOID)*(m_nMax - pData->nCount));		pData->nCount = m_nMax;		::TlsSetValue(m_tlsIndex, pData);	}	pData->pData[nSlot] = pValue;}void* CSlotThreadData::GetThreadValue(int nSlot){	CThreadData* pData = (CThreadData*)::TlsGetValue(m_tlsIndex);	if (pData == NULL || pData->nCount <= nSlot)	{		return NULL;	}	return pData->pData[nSlot];}void CSlotThreadData::SlotFree(int nSlot){	::EnterCriticalSection(&m_cs);	CThreadData* pData = m_list;	while (pData != NULL)	{		if (pData->nCount > nSlot)		{			delete (CNoTrackObject*)pData->pData[nSlot];			pData->pData[nSlot] = NULL;		}		pData = pData->pNext;	}	m_pSlotData[nSlot].dwFlags &= ~SLOT_USED;	::LeaveCriticalSection(&m_cs);}void CSlotThreadData::DeleteValues(HINSTANCE hInst, bool bAll){	::EnterCriticalSection(&m_cs);	if (!bAll)	{		CThreadData* pData = (CThreadData*)::TlsGetValue(m_tlsIndex);		if (pData != NULL)		{			DeleteValues(pData, hInst);		}	}	else	{		CThreadData* pData = m_list;		while (pData != NULL)		{			CThreadData* pNextData = pData->pNext;			DeleteValues(pData, hInst);			pData = pNextData;		}	}	::LeaveCriticalSection(&m_cs);}void CSlotThreadData::DeleteValues(CThreadData* pData, HINSTANCE hInst){	bool bDelete = true;	for (int i = 1; i<pData->nCount; i++)	{		if (m_pSlotData[i].hInst == hInst || hInst == NULL)		{			delete (CNoTrackObject*)pData->pData[i];			pData->pData[i] = NULL;		}		else		{			if (m_pSlotData[i].hInst != NULL)			{				bDelete = false;			}		}	}	if (bDelete)	{		::EnterCriticalSection(&m_cs);		m_list.Remove(pData);		::LeaveCriticalSection(&m_cs);		::LocalFree(pData->pData);		delete pData;		::TlsSetValue(m_tlsIndex, NULL);	}}CSlotThreadData::~CSlotThreadData(){	CThreadData* pData = m_list;	while (pData != NULL)	{		CThreadData* p = pData->pNext;		DeleteValues(pData, NULL);		pData = p;	}	if (m_tlsIndex != (DWORD)-1)	{		::TlsFree(m_tlsIndex);	}	if (m_pSlotData != NULL)	{		HGLOBAL hSlotData = ::GlobalHandle(m_pSlotData);		::GlobalUnlock(hSlotData);		::GlobalFree(hSlotData);	}	::DeleteCriticalSection(&m_cs);	cout << "~CSlotThreadData()" << endl;}extern CRITICAL_SECTION m;BYTE __afxThreadData[sizeof(CSlotThreadData)];CSlotThreadData* _afxThreadData;CNoTrackObject* CThreadLocalObject::GetData(CNoTrackObject* (*pCreateObject)()){	::EnterCriticalSection(&m);	if (_afxThreadData == NULL || m_nSlot == 0)	{		if (_afxThreadData == NULL)		{			_afxThreadData = new (__afxThreadData)CSlotThreadData;		}		m_nSlot = _afxThreadData->SlotAlloc();	} 	::LeaveCriticalSection(&m);	CNoTrackObject* pValue = (CNoTrackObject*)_afxThreadData->GetThreadValue(m_nSlot);	if (pValue == NULL)	{		pValue = (*pCreateObject)();//new CNoTrackObject		_afxThreadData->SetThreadValue(m_nSlot, pValue);	}	return pValue;}CNoTrackObject* CThreadLocalObject::GetDataNA(){	if (_afxThreadData == NULL || m_nSlot == 0)	{		return NULL;	}	return (CNoTrackObject*)_afxThreadData->GetThreadValue(m_nSlot);}CThreadLocalObject::~CThreadLocalObject(){	cout << "~CThreadLocalObject()" << endl;	if (m_nSlot != 0 && _afxThreadData != NULL)		_afxThreadData->SlotFree(m_nSlot);	m_nSlot = 0;}#endif


main.cpp文件

#include "stdafx.h"#include "_AFXTLS_.h"using namespace std;using std::cout;using std::endl;#include<process.h>CRITICAL_SECTION m;extern CSlotThreadData* _afxThreadData;struct CMyThreadData :public CNoTrackObject{	int nSomeData;};//THREAD_LOCAL(CMyThreadData, g_myThreadData)CThreadLocal<CMyThreadData> g_myThreadData;void ShowData();UINT WINAPI ThreadFunc(LPVOID lpParam){	CMyThreadData* t = g_myThreadData;	t->nSomeData = (int)lpParam;	//g_myThreadData->nSomeData = (int)lpParam;	ShowData();	return 0;}void test12(){	HANDLE h[10];	UINT  uID;		::InitializeCriticalSection(&m);	for (int i = 0; i < 10; i++)		h[i] = (HANDLE) ::_beginthreadex(NULL, 0, ThreadFunc, (void*)i, 0, &uID);	::WaitForMultipleObjects(10, h, TRUE, INFINITE);	for (int i = 0; i < 10; i++)		::CloseHandle(h[i]);		//delete _afxThreadData;}void test13(){	HANDLE h;	//HANDLE h2;	UINT uID;	int i = 1;	int j = 2;	//_afxThreadData = new(__afxThreadData)CSlotThreadData;	::InitializeCriticalSection(&m);	h = (HANDLE)::_beginthreadex(NULL, 0, ThreadFunc, (void*)i, 0, &uID);	//h2 = (HANDLE)::_beginthreadex(NULL, 0, ThreadFunc, (void*)j, 0, &uID);	::WaitForSingleObject(h, INFINITE);		//::WaitForSingleObject(h2, INFINITE);	::CloseHandle(h);	/**if (_afxThreadData != NULL)	{		delete[] _afxThreadData;		_afxThreadData = NULL;	}**/	::DeleteCriticalSection(&m);	//::CloseHandle(h2);}void ShowData(){	int nData = g_myThreadData->nSomeData;	printf("ThreadID::%-5d,nSomeData=%d/n", ::GetCurrentThreadId(), nData);}int _tmain(int argc, _TCHAR* argv[]){	test13();	return 0;}

if (_afxThreadData == NULL || m_nSlot == 0)	{		if (_afxThreadData == NULL)		{			_afxThreadData = new (__afxThreadData)CSlotThreadData;		}		m_nSlot = _afxThreadData->SlotAlloc();	}

这是CThreadLocalObject::GetData方法中的部分代码;
原作者在检验_afxThreadData和初始化的时候,并没有考虑到多线程的影响,这导致实际上_afxThreadData可能会多次初始化,


通过调试,或者为CSlotThreadData构造函数添加输出,我们都能观察到,程序构造不止了一个CSlotThreadData对象。未解决这个问题,我在上面这段代码的基础上做了改进,


首先添加一个全局CRITICAL_SECTION  m;变量在主线程中初始化::InitializeCriticalSection(&m);,并在上面这段代码的前后添加::EnterCriticalSection(&m);和::LeaveCriticalSection(&m);

::EnterCriticalSection(&m);	if (_afxThreadData == NULL || m_nSlot == 0)	{		if (_afxThreadData == NULL)		{			_afxThreadData = new (__afxThreadData)CSlotThreadData;		}		m_nSlot = _afxThreadData->SlotAlloc();	} 	::LeaveCriticalSection(&m);


这样,各个线程实现了共享同一个_afxThreadData。而不会重复构造CSlotThreadData。但还有问题尚未解决,实际上这个_afxThreadData直到程序结束也未调用过析构函数,这就造成了内存泄漏,我本想在主线程中人工的添加delete ——afThreadData,但编译器报错。特写这篇日志标记这个错误,以往有人解决,或者以后在探寻。



最新文章

123

最新摄影

微信扫一扫

第七城市微信公众平台