?? afxtls.cpp
字號:
///////////////////////////////////////////////////////
// AFXTLS.CPP文件
#include "_AFXTLS_.H"
//---------------------------------------
void CSimpleList::AddHead(void* p)
{
*GetNextPtr(p) = m_pHead;
m_pHead = p;
}
BOOL CSimpleList::Remove(void* p)
{
if(p == 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(pTest);
// 如果找到,就將元素移除
if(pTest != NULL)
{
*GetNextPtr(pTest) = *GetNextPtr(p);
bResult = TRUE;
}
}
return bResult;
}
//-------------------CThreadSlotData類----------------------//
BYTE __afxThreadData[sizeof(CThreadSlotData)]; // 為下面的_afxThreadData變量提供內存
CThreadSlotData* _afxThreadData; // 定義全局變量_afxThreadData來為全局變量分配空間
struct CSlotData
{
DWORD dwFlags; // 槽的使用標志(被分配/未被分配)
HINSTANCE hInst;// 占用此槽的模塊句柄
};
struct CThreadData : public CNoTrackObject
{
CThreadData* pNext; // CSimpleList類要使用此成員
int nCount; // 數組元素的個數
LPVOID* pData; // 數組的首地址
};
#define SLOT_USED 0x01 // CSlotData結構中dwFlags成員的值為0x01時表示該槽已被使用
CThreadSlotData::CThreadSlotData()
{
m_list.Construct(offsetof(CThreadData, pNext)); // 初始化CTypedSimpleList對象
m_nMax = 0;
m_nAlloc = 0;
m_nRover = 1; // 我們假定Slot1還未被分配(第一個槽(Slot0)總是保留下來不被使用)
m_pSlotData = NULL;
m_tlsIndex = ::TlsAlloc(); // 使用系統的TLS申請一個索引
::InitializeCriticalSection(&m_cs); // 初始化關鍵段變量
}
int CThreadSlotData::AllocSlot()
{
::EnterCriticalSection(&m_cs); // 進入臨界區(也叫關鍵段)
int nAlloc = m_nAlloc;
int nSlot = m_nRover;
if(nSlot >= nAlloc || m_pSlotData[nSlot].dwFlags & SLOT_USED)
{
// 搜索m_pSlotData,查找空槽(SLOT)
for(nSlot = 1; nSlot < nAlloc && m_pSlotData[nSlot].dwFlags & SLOT_USED; nSlot ++) ;
// 如果不存在空槽,申請更多的空間
if(nSlot >= nAlloc)
{
// 增加全局數組的大小,分配或再分配內存以創建新槽
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);
// 將新申請的空間初始化為0
memset(pSlotData + m_nAlloc, 0, (nNewAlloc - nAlloc)*sizeof(CSlotData));
m_nAlloc = nNewAlloc;
m_pSlotData = pSlotData;
}
}
// 調整m_nMax的值,以便為各線程的私有數據分配內存
if(nSlot >= m_nMax)
m_nMax = nSlot + 1;
m_pSlotData[nSlot].dwFlags |= SLOT_USED;
// 更新m_nRover的值(我們假設下一個槽未被使用)
m_nRover = nSlot + 1;
::LeaveCriticalSection(&m_cs);
return nSlot; // 返回的槽號可以被FreeSlot, GetThreadValue, SetValue函數使用了
}
void CThreadSlotData::FreeSlot(int nSlot)
{
::EnterCriticalSection(&m_cs);
// 刪除所有線程中的數據
CThreadData* pData = m_list;
while(pData != NULL)
{
if(nSlot < pData->nCount)
{
delete (CNoTrackObject*)pData->pData[nSlot];
pData->pData[nSlot] = NULL;
}
pData = pData->pNext;
}
// 將此槽號標識為未被使用
m_pSlotData[nSlot].dwFlags &= ~SLOT_USED;
::LeaveCriticalSection(&m_cs);
}
inline void* CThreadSlotData::GetThreadValue(int nSlot)
{
CThreadData* pData = (CThreadData*)::TlsGetValue(m_tlsIndex);
if(pData == NULL || nSlot >= pData->nCount)
return NULL;
return pData->pData[nSlot];
}
void CThreadSlotData::SetValue(int nSlot, void* pValue)
{
// 通過TLS索引得到我們為線程安排的私有存儲空間
CThreadData* pData = (CThreadData*)::TlsGetValue(m_tlsIndex);
// 為線程私有數據申請內存空間
if((pData == NULL || nSlot >= pData->nCount) && pValue != NULL)
{
// pData的值為空,表示該線程第一次訪問線程私有數據
if(pData == NULL)
{
pData = new CThreadData;
pData->nCount = 0;
pData->pData = NULL;
// 將新申請的內存的地址添加到全局列表中
::EnterCriticalSection(&m_cs);
m_list.AddHead(pData);
::LeaveCriticalSection(&m_cs);
}
// pData->pData指向真正的線程私有數據,下面的代碼將私有數據占用的空間增長到m_nMax指定的大小
if(pData->pData == NULL)
pData->pData = (void**)::GlobalAlloc(LMEM_FIXED, m_nMax*sizeof(LPVOID));
else
pData->pData = (void**)::GlobalReAlloc(pData->pData, m_nMax*sizeof(LPVOID), LMEM_MOVEABLE);
// 將新申請的內存初始話為0
memset(pData->pData + pData->nCount, 0,
(m_nMax - pData->nCount) * sizeof(LPVOID));
pData->nCount = m_nMax;
::TlsSetValue(m_tlsIndex, pData);
}
// 設置線程私有數據的值
pData->pData[nSlot] = pValue;
}
void CThreadSlotData::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.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->pData[i];
pData->pData[i] = NULL;
}
else
{
// 還有其它模塊在使用,不要刪除數據
if(pData->pData[i] != NULL)
bDelete = FALSE;
}
}
if(bDelete)
{
// 從列表中移除
::EnterCriticalSection(&m_cs);
m_list.Remove(pData);
::LeaveCriticalSection(&m_cs);
::LocalFree(pData->pData);
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(m_pSlotData);
}
::DeleteCriticalSection(&m_cs);
}
//---------------------------------------
void* CNoTrackObject::operator new(size_t nSize)
{
// 申請一塊帶有GMEM_FIXED和GMEM_ZEROINIT標志的內存
void* p = ::GlobalAlloc(GPTR, nSize);
return p;
}
void CNoTrackObject::operator delete(void* p)
{
if(p != NULL)
::GlobalFree(p);
}
//----------------------------CThreadLocalObject 類--------------------------------//
CNoTrackObject* CThreadLocalObject::GetData(CNoTrackObject* (*pfnCreateObject)())
{
if(m_nSlot == 0)
{
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);
}
CThreadLocalObject::~CThreadLocalObject()
{
if(m_nSlot != 0 && _afxThreadData != NULL)
_afxThreadData->FreeSlot(m_nSlot);
m_nSlot = 0;
}
//------------------------------------------
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -