关于线程局部存储代码出错分析讨论

来源:互联网 发布:linux查询cpu和内存 编辑:程序博客网 时间:2024/06/02 22:38

忙了一两天把这个代码敲完了,但是在调试时候出 了一些问题,慕思苦想还没搞定这个问题多以请大家指点指点

_AFXTLS.h文件如下:

/******************************************************************* 
 *  Copyright(c) 2000-2016 Company Name 
 *  All rights reserved. 
 *   
 *  文件名称: _AFXTLS.h
 *  简要描述: 
 *   
 *  创建日期: 2016.6.30
 *  作者: 
 *  说明: 
 ******************************************************************/  
#ifndef __AFXTLS_H__
#define __AFXTLS_H__


#include "stdafx.h"
#include "windows.h"
#include <rpcndr.h>


#define offsetof(s,m) (size_t)&(((s*)0)->m)
#define SLOT_USED 0x01


// --------CSimpList - provide a simple function------------------
class CSimpList
{
public:
~CSimpList();
void **GetNextPtr(void *p) const
{
return  (void **)((BYTE*)p+m_nNextOffset);
}
CSimpList(int nNextOffSet = 0);
void Construct(int nNextOffSet);
BOOL IsEmpty()const;
void AddHead(void *p);
void RemoveAll();
void* GetHead()const;
void *GetNext(void *p)const;
BOOL Remove(void *p);
private:
void *m_pHead;//指向链表第一个位置
size_t m_nNextOffset;//数据结构中pNext成员的偏移量
};
inline CSimpList::CSimpList(int nNextOffSet)
{
m_pHead = NULL;
this->m_nNextOffset = nNextOffSet;
}
inline CSimpList::~CSimpList()
{
}


inline void CSimpList::Construct(int nNextOffSet)
{
this->m_nNextOffset = nNextOffSet;
}
inline BOOL CSimpList::IsEmpty() const
{
return m_pHead ==NULL;
}
inline void CSimpList::RemoveAll()
{
m_pHead =NULL;
}
inline void* CSimpList::GetHead() const
{
return m_pHead;
}
inline void * CSimpList::GetNext(void *p) const
{
return GetNextPtr(p);
}


inline BOOL CSimpList::Remove(void *p)
{
if (m_pHead == NULL)
{
return FALSE;
}
bool bResult = FALSE;
if(p == m_pHead)
{
m_pHead  = *GetNextPtr(p);
bResult = true;
}
else
{
void *pTest = m_pHead;
while (pTest !=NULL && *GetNextPtr(pTest)!=p)
{
pTest = *GetNextPtr(p);
}
if(pTest !=NULL)
{
*GetNextPtr(pTest) = *GetNextPtr(p);
bResult = true;
}
}
return bResult;
}
inline void CSimpList::AddHead(void *p)
{
*GetNextPtr(p)=m_pHead;
m_pHead = p;

}


// --------CTypedSimpleList - extend CSimpleList------------------
template<class TYPE>
class CTypedSimpleList:public CSimpList
{
public:
CTypedSimpleList(int nNextOffSet = 0): CSimpList(nNextOffSet){}
void AddHead(TYPE p)
{
CSimpList::AddHead((void *)p);
}
TYPE GetHead()
{
return (TYPE)CSimpList::GetHead();
}
TYPE GetNext(TYPE p)
{
return (TYPE)CSimpList::GetNext(p);
}
BOOL Remove(TYPE p)
{
return CSimpList::Remove(p);
}


/*
CTypeSimpleList <CThreadData *>list
CThreadData *pData = list;等价于pData = list.GetHead
*/
operator TYPE()//直接引用类的对象会调用此函数
{
return  (TYPE)CSimpList::GetHead();
}


};
// --------CNoTrackObject --------------------------------------------
class CNoTrackObject //负责私有线程低层内存分配
{
public:
void *operator new(size_t nSize);
void operator delete(void *p);
virtual ~CNoTrackObject();


};
struct CThreadData :public CNoTrackObject   //线程的私有数据
{
CThreadData *pNext;//指向下一个结构指针
LPVOID *Data; //真正指向的数据
int nCount; // current size of pData
};
// --------CSlotData --------------------------------------------
struct CSlotData
{
DWORD dwflag; //槽的使用标志,使用或未使用
HINSTANCE hInst;
};
// --------CThreadSlotData --------------------------------------------


class CThreadSlotData
{
public:
CThreadSlotData();
~CThreadSlotData();
int AllocSlot();//分配槽
void FreeSlot(int nSlot);//释放槽
void *GetThreadValue(int nSlot);
void SetValue(int nSlot,void *pValue);
void DeleteValue(HINSTANCE hinst,BOOL bAll =FALSE);
DWORD m_tlsIndex;
CTypedSimpleList <CThreadData *> m_list;
int m_nAlloc; //m_pSlotData所指向的数组大小
int m_nMax; //占用槽的最大数
CSlotData * m_pSlotdata;//全局数组的首地址
int m_nRover; //为了快速找到空闲的槽而设定的值
CRITICAL_SECTION m_cs;
void *operator new (size_t,void *p)
{
return p;
}
void DeleteValues(CThreadData *pData,HINSTANCE hinst);


};




class CThreadLocalObject
{
public:
CThreadLocalObject();
~CThreadLocalObject();
//属性成员,用于取得保存在线程局部的变量中的指针
CNoTrackObject * GetData(CNoTrackObject* (*pfnCreateObject)());
CNoTrackObject * GetDataNA();//返回变量的值


//具体实现
DWORD m_nSlot;


};


template <class TYPE>
class CThreadLocal:public CThreadLocalObject
{
public:
TYPE *GetData()
{
TYPE *pData = (TYPE *)CThreadLocalObject::GetData(&CreateObject);
return pData;
}
TYPE GetDataNA()
{
TYPE *pData = (TYPE *)CThreadLocalObject::GetDataNA();
return pData;
}
operator TYPE*()
{
return GetData();
}
TYPE* operator->()
{
return GetData();
}


static CNoTrackObject* CreateObject()
{
return new TYPE;
}
};


#endif

_AFXTLS.cpp文件如下:

#include "stdafx.h"
#include "_AFXTLS.h"


#include "windows.h"
#include <winbase.h>


void *CNoTrackObject::operator new(size_t nSize)
{
void *p = ::GlobalAlloc(GPTR,nSize);
return p;
}


void CNoTrackObject::operator delete(void *p)
{
::GlobalFree(p);
}


CNoTrackObject::~CNoTrackObject()
{
}


CThreadSlotData::CThreadSlotData()
{
m_list.Construct(offsetof(CThreadData,pNext));
m_nMax = 0;
m_nAlloc = 0;
m_nRover = 1; //假设SLOT1还未分配,Slot0总是被保留
m_pSlotdata = NULL;//指向槽的指针
m_tlsIndex = ::TlsAlloc();
::InitializeCriticalSection(&m_cs);
}


int CThreadSlotData::AllocSlot()
{
::EnterCriticalSection(&m_cs);




int nAlloc = m_nAlloc;
int nSlot = m_nRover;
if (nSlot>=nAlloc || m_pSlotdata[nSlot].dwflag & SLOT_USED)
{
for (nSlot = 1;nSlot<nAlloc && m_pSlotdata[nSlot].dwflag & SLOT_USED;nSlot++)
{
//如果不存在空槽申请更多的空间
int  nNewAlloc =nAlloc+32;
HGLOBAL hSlotData;
if (m_pSlotdata  == NULL)
{
hSlotData = ::GlobalAlloc(GMEM_MOVEABLE,nNewAlloc * sizeof(CSlotData));
}
else
{
hSlotData = ::GlobalHandle(m_pSlotdata);
::GlobalUnlock(hSlotData);
hSlotData = GlobalReAlloc(hSlotData,nNewAlloc * sizeof(CSlotData),GMEM_MOVEABLE);
}
CSlotData *pSlotData = (CSlotData*)GlobalLock(hSlotData);
m_nAlloc  = nNewAlloc;
m_pSlotdata = pSlotData;


}
}
if(nSlot >= m_nMax)
{
m_nMax = nSlot+1;
}
m_pSlotdata[nSlot].dwflag |=SLOT_USED;//标志为该标记已经使用
m_nRover = nSlot+1;//更新m_nRover假设下一个槽未被使用
::LeaveCriticalSection(&m_cs);

return nSlot;
}
BYTE __afxThreadData[sizeof CThreadData]; //为下面的__afxThreadData变量提供内存
CThreadSlotData *_afxThreadData; //定义全局变量__afxThreadData来为全局变量分配内存


void CThreadSlotData::SetValue(int nSlot,void *pValue)
{
CThreadData *pData = (CThreadData* )::TlsGetValue(m_tlsIndex);//通过tls索引为线程分配私有空间
//为线程私有数据分配空间
if((pData ==NULL || nSlot>=pData->nCount)&& pValue !=NULL)
{
if (pData ==NULL)
{
pData = new CThreadData;
pData->nCount = 0;
pData->Data = NULL;


//将新申请的内存地址添加到全局变量中
::EnterCriticalSection(&m_cs);
m_list.AddHead(pData);
::LeaveCriticalSection(&m_cs);
}

//pData->data 指向真正的线程私有数据
//下面的代码将私有的数据占用的空间增长到m_nMax指定的大小
if (pData->Data ==NULL)
{
pData->Data =(void **) GlobalAlloc(LMEM_FIXED,m_nMax*sizeof(LPVOID));

else
{
pData->Data = (void **)::GlobalReAlloc(pData->Data,m_nMax*sizeof(LPVOID),LMEM_MOVEABLE);
}


//将申请的内存初始化为0;
memset(&(pData->Data) + pData->nCount,0,(m_nMax-pData->nCount)*sizeof(LPVOID));
pData->nCount=m_nMax;
::TlsSetValue(m_tlsIndex,pData);
}
pData->Data[nSlot] = pValue;
}


void *CThreadSlotData::GetThreadValue(int nSlot)
{
CThreadData *pData=(CThreadData *)TlsGetValue(m_tlsIndex);
if (pData==NULL || nSlot>=pData->nCount)
{
return NULL;
}
return pData->Data[nSlot];
}


void CThreadSlotData:: FreeSlot(int nSlot)
{
::EnterCriticalSection(&m_cs);
CThreadData *pData = m_list;
while (pData !=NULL)
{
if (nSlot<pData->nCount)
{
delete((CNoTrackObject*)pData->Data[nSlot]);
pData->Data[nSlot] = NULL;
pData = pData->pNext;
}


}
//将此槽标示为未被使用
m_pSlotdata[nSlot].dwflag &=~SLOT_USED;
::LeaveCriticalSection(&m_cs);
}


void CThreadSlotData::DeleteValue(HINSTANCE hinst,BOOL bAll /*=FALSE*/)
{
::EnterCriticalSection(&m_cs);
if (!bAll)
{
//仅仅删除当前线程的线程局部存储占用空间
CThreadData *pData=(CThreadData*)TlsGetValue(m_tlsIndex);
if (pData !=NULL)
{
DeleteValues(pData,hinst);
}
else
{
//删除所有线程的线程局部存储占用的空间
CThreadData *pData = m_list.GetHead();
while (pData !=NULL)
{
CThreadData *pNextData = pData->pNext;
DeleteValues(pData,hinst);
pData = pNextData;
}
}


}
::LeaveCriticalSection(&m_cs);
}
void CThreadSlotData::DeleteValues(CThreadData *pData,HINSTANCE hinst)
{
//释放表中每一个元素
BOOL bDelete = TRUE;
for (int i = 1;i<pData->nCount;i++)
{
if (hinst ==NULL || m_pSlotdata[i].hInst ==hinst)
{
//hinst匹配,删除数据
delete((CNoTrackObject*)pData->Data[i]);
pData->Data[i] = NULL;

else
{
//还有其他模块在使用不要删除数据
if(pData->Data[i]!=NULL)
bDelete =FALSE;
}
if (bDelete)
{
//从列表中删除
::EnterCriticalSection(&m_cs);
m_list.Remove(pData);
::LeaveCriticalSection(&m_cs);
::LocalFree(pData->Data);
delete pData;
//清除TLS索引以免重用
::TlsSetValue(m_tlsIndex,NULL);
}
}
}


CThreadSlotData::~CThreadSlotData()
{
CThreadData *pData= m_list;
while (pData != NULL)
{
CThreadData* pDataNext = pData->pNext;
DeleteValues(pData,NULL);
pData = pData->pNext;
}
if (m_tlsIndex != (DWORD)-1)
{
::TlsFree(m_tlsIndex);
}
if (m_pSlotdata !=NULL)
{
HGLOBAL hSlotData = ::GlobalHandle(m_pSlotdata);
::GlobalUnlock(hSlotData);
::GlobalFree(hSlotData);
}
::DeleteCriticalSection(&m_cs);
}






CThreadLocalObject::CThreadLocalObject()
{
}


CThreadLocalObject::~CThreadLocalObject()
{
if (m_nSlot!=0 &&_afxThreadData!=NULL)
{
_afxThreadData->FreeSlot(m_nSlot);
m_nSlot = 0;
}
}


CNoTrackObject * CThreadLocalObject::GetData(CNoTrackObject* (*pfnCreateObject)())
{
if (m_nSlot = NULL)
{
if (_afxThreadData = NULL)
{
_afxThreadData = new(__afxThreadData)CThreadSlotData;
m_nSlot = _afxThreadData->AllocSlot();
}
}
CNoTrackObject *pValue = (CNoTrackObject*)_afxThreadData->GetThreadValue(m_nSlot);
if (pValue==NULL)
{
pValue = (*pfnCreateObject)();
_afxThreadData->SetValue(m_nSlot,pValue);
}
return pValue;

}
CNoTrackObject * CThreadLocalObject::GetDataNA()
{
if (m_nSlot == 0||_afxThreadData == 0)
{
return NULL;
}
return (CNoTrackObject*)_afxThreadData->GetThreadValue(m_nSlot);
}



主文件TLS.cpp文件如下:

// TLS.cpp : 定义控制台应用程序的入口点。
//


#include "stdafx.h"
#include "windows.h"
#include "_AFXTLS.h"
#include "process.h"

#pragma comment(lib,"ws2_32.lib")

void ShowData();
struct CMyThreadData:public CNoTrackObject
{
int nSomeData;
};


CThreadLocal<CMyThreadData>g_myThreadData;
UINT __stdcall ThreadFunc(LPVOID lpParam)
{
g_myThreadData->nSomeData =(int)lpParam;
ShowData();
return 0;
}


int _tmain(int argc, _TCHAR* argv[])\
{

HANDLE h[10];
UINT uID;


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]);
}

}

void ShowData()
{
int nData = g_myThreadData->nSomeData;
printf("Thread ID:%-5d,nSomeData = %d\n",::GetCurrentThreadId(),nData);

}


0 0
原创粉丝点击