TLS(執行緒區域性儲存)模擬控制代碼的實現
阿新 • • 發佈:2019-02-07
這是今天做一個郵件傳送模組把一個類包裝成Win32 API形式呼叫時想到的。簡單的實現了一下控制代碼的概念,對於理解核心物件和控制代碼的概念有一定幫助,看起來還頗像那麼回事,呵呵。不過這裡的“控制代碼表”是藉助了TLS實現的。
值得一提的是,這個小例子也實現了引用計數的概念,就像執行緒一樣,剛建立時,執行緒物件的控制代碼計數是2,因此要CloseHandle一次。下次需要控制代碼需要重新OpenThread。這裡的物件控制代碼的引用計數也是2,因此剛建立的控制代碼關掉後,物件不會被刪除。當計數遞減到1時就刪除這個物件。下面是例子的原始碼:
#include <Windows.h> #include <stdio.h> #include <list> using namespace std; #pragma warning(disable:4996) class TEST { public: TEST(LPCSTR lpName) { refCount = 2; x = 0; strcpy(name, lpName); printf(“X value is %d \n”, x); } ~TEST() { printf(“Destructor \n”); } void EditX(DWORD value) { x = value; } public: DWORD refCount; char name[10]; DWORD x; }; list<TEST *> Obj; HANDLE WINAPI Create(LPCSTR lpName) { DWORD index = TlsAlloc(); if (index == TLS_OUT_OF_INDEXES) { return NULL; } TEST *p = new TEST(lpName); Obj.push_back(p); if (!TlsSetValue(index, p)) { return NULL; } return (HANDLE)index; } HANDLE WINAPI Open(LPCSTR lpName) { for (list<TEST *>::iterator it = Obj.begin(), end = Obj.end(); it != end; ++it) { if (0 == strcmp((*it)->name, lpName)) { DWORD index = TlsAlloc(); if (index == TLS_OUT_OF_INDEXES) { return NULL; } if (!TlsSetValue(index, *it)) { return NULL; } (*it)->refCount++; return (HANDLE)index; } } return NULL; } BOOL WINAPI Close(HANDLE h) { TEST *p = (TEST *)TlsGetValue((DWORD)h); if (--(p->refCount) == 0) { for (list<TEST *>::iterator it = Obj.begin(), end = Obj.end(); it != end; /*nothing*/) { if (0 == strcmp((*it)->name, p->name)) { Obj.erase(it++); } else { ++it; } } delete p; } TlsFree((DWORD)h); return TRUE; } BOOL WINAPI Edit(HANDLE h, DWORD value) { TEST *p = (TEST *)TlsGetValue((DWORD)h); if (p == NULL) { return FALSE; } p->EditX(value); printf(“X value is %d \n”, p->x); return TRUE; } int main() { HANDLE h = Create(“Gooleer”); if (h != NULL) { Edit(h, 1); Close(h); } Edit(h, 2); h = Open(“Gooleer”); if (h != NULL) { Edit(h, 3); Close(h); } return 0; }