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

本人自学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 0x01

CSlotThreadData::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,但编译器报错。特写这篇日志标记这个错误,以往有人解决,或者以后在探寻。



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值