Megjegyzés
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhat bejelentkezni vagy módosítani a címtárat.
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhatja módosítani a címtárat.
Ez a szakasz egy DLL belépésipont-függvény használatát mutatja be egy szál helyi tárolási (TLS) indexének beállításához, amely privát tárolót biztosít egy többszálas folyamat minden szálához.
A TLS-index egy globális változóban van tárolva, így az az összes DLL-függvény számára elérhetővé válik. Ez a példa feltételezi, hogy a DLL globális adatai nincsenek megosztva, mivel a TLS-index nem feltétlenül ugyanaz a DLL-t betöltő összes folyamat esetében.
A belépési pont függvény a TlsAlloc függvénnyel foglal le egy TLS-indexet, amikor egy folyamat betölti a DLL-t. Ezután minden szál ezt az indexet használhatja a saját memóriablokkjára mutató mutató tárolására.
Ha a belépési pont függvény meghívása a DLL_PROCESS_ATTACH értékkel történik, a kód a következő műveleteket hajtja végre:
- A TLS-index lefoglalásához a TlsAlloc függvényt használja.
- Lefoglal egy memóriablokkot, amelyet kizárólag a folyamat kezdeti szála használ.
- A TLS-indexet a TlsSetValue függvény hívásában használja a memóriablokk címének tárolására az indexhez társított TLS-ponton.
Minden alkalommal, amikor a folyamat létrehoz egy új szálat, a rendszer meghívja a belépési pont függvényt a DLL_THREAD_ATTACH értékkel. A belépési pont függvény ezután lefoglal egy memóriablokkot az új szálhoz, és a TLS-index használatával egy mutatót tárol hozzá.
Ha egy függvény hozzáférést igényel a TLS-indexhez társított adatokhoz, adja meg az indexet a TlsGetValue függvény hívásában. Ez lekéri a hívószál TLS szlotjának tartalmát, amely ebben az esetben egy mutató az adatok memóriablokkjára. Ha egy folyamat betöltési idő csatolást használ ezzel a DLL-vel, a belépési pont függvény elegendő a szál helyi tárolójának kezeléséhez. A futásidejű csatolást használó folyamatokkal problémák léphetnek fel, mert a rendszer nem hívja meg a belépési pont függvényt az LoadLibrary függvény meghívása előtt, így a rendszer nem foglalja le a TLS-memóriát ezekhez a szálakhoz. Ez a példa a TlsGetValue függvény által visszaadott érték ellenőrzésével és a memória kiosztásával oldja meg ezt a problémát, ha az érték azt jelzi, hogy nincs beállítva a szálhoz tartozó TLS-pont.
Ha minden szálnak már nem kell TLS-indexet használnia, szabadítson fel egy memóriát, amelynek mutatója a TLS-ponton van tárolva. Ha az összes szál befejezte a TLS-index használatát, az index kiadásához használja a TlsFree függvényt.
Amikor egy szál leáll, a belépési pont függvény meghívása a DLL_THREAD_DETACH értékkel történik, és a szál memóriája felszabadul. Amikor egy folyamat leáll, a belépési pont függvény a DLL_PROCESS_DETACH értékkel lesz meghívva, és a TLS-indexben lévő mutató által hivatkozott memória felszabadul.
// The DLL code
#include <windows.h>
static DWORD dwTlsIndex; // address of shared memory
// DllMain() is the entry-point function for this DLL.
BOOL WINAPI DllMain(HINSTANCE hinstDLL, // DLL module handle
DWORD fdwReason, // reason called
LPVOID lpvReserved) // reserved
{
LPVOID lpvData;
BOOL fIgnore;
switch (fdwReason)
{
// The DLL is loading due to process
// initialization or a call to LoadLibrary.
case DLL_PROCESS_ATTACH:
// Allocate a TLS index.
if ((dwTlsIndex = TlsAlloc()) == TLS_OUT_OF_INDEXES)
return FALSE;
// No break: Initialize the index for first thread.
// The attached process creates a new thread.
case DLL_THREAD_ATTACH:
// Initialize the TLS index for this thread.
lpvData = (LPVOID) LocalAlloc(LPTR, 256);
if (lpvData != NULL)
fIgnore = TlsSetValue(dwTlsIndex, lpvData);
break;
// The thread of the attached process terminates.
case DLL_THREAD_DETACH:
// Release the allocated memory for this thread.
lpvData = TlsGetValue(dwTlsIndex);
if (lpvData != NULL)
LocalFree((HLOCAL) lpvData);
break;
// DLL unload due to process termination or FreeLibrary.
case DLL_PROCESS_DETACH:
// Release the allocated memory for this thread.
lpvData = TlsGetValue(dwTlsIndex);
if (lpvData != NULL)
LocalFree((HLOCAL) lpvData);
// Release the TLS index.
TlsFree(dwTlsIndex);
break;
default:
break;
}
return TRUE;
UNREFERENCED_PARAMETER(hinstDLL);
UNREFERENCED_PARAMETER(lpvReserved);
}
// The export mechanism used here is the __declspec(export)
// method supported by Microsoft Visual Studio, but any
// other export method supported by your development
// environment may be substituted.
#ifdef __cplusplus // If used by C++ code,
extern "C" { // we need to export the C interface
#endif
__declspec(dllexport)
BOOL WINAPI StoreData(DWORD dw)
{
LPVOID lpvData;
DWORD * pData; // The stored memory pointer
lpvData = TlsGetValue(dwTlsIndex);
if (lpvData == NULL)
{
lpvData = (LPVOID) LocalAlloc(LPTR, 256);
if (lpvData == NULL)
return FALSE;
if (!TlsSetValue(dwTlsIndex, lpvData))
return FALSE;
}
pData = (DWORD *) lpvData; // Cast to my data type.
// In this example, it is only a pointer to a DWORD
// but it can be a structure pointer to contain more complicated data.
(*pData) = dw;
return TRUE;
}
__declspec(dllexport)
BOOL WINAPI GetData(DWORD *pdw)
{
LPVOID lpvData;
DWORD * pData; // The stored memory pointer
lpvData = TlsGetValue(dwTlsIndex);
if (lpvData == NULL)
return FALSE;
pData = (DWORD *) lpvData;
(*pdw) = (*pData);
return TRUE;
}
#ifdef __cplusplus
}
#endif
Az alábbi kód az előző példában definiált DLL-függvények használatát mutatja be.
#include <windows.h>
#include <stdio.h>
#define THREADCOUNT 4
#define DLL_NAME TEXT("testdll")
VOID ErrorExit(LPSTR);
extern "C" BOOL WINAPI StoreData(DWORD dw);
extern "C" BOOL WINAPI GetData(DWORD *pdw);
DWORD WINAPI ThreadFunc(VOID)
{
int i;
if(!StoreData(GetCurrentThreadId()))
ErrorExit("StoreData error");
for(i=0; i<THREADCOUNT; i++)
{
DWORD dwOut;
if(!GetData(&dwOut))
ErrorExit("GetData error");
if( dwOut != GetCurrentThreadId())
printf("thread %d: data is incorrect (%d)\n", GetCurrentThreadId(), dwOut);
else printf("thread %d: data is correct\n", GetCurrentThreadId());
Sleep(0);
}
return 0;
}
int main(VOID)
{
DWORD IDThread;
HANDLE hThread[THREADCOUNT];
int i;
HMODULE hm;
// Load the DLL
hm = LoadLibrary(DLL_NAME);
if(!hm)
{
ErrorExit("DLL failed to load");
}
// Create multiple threads.
for (i = 0; i < THREADCOUNT; i++)
{
hThread[i] = CreateThread(NULL, // default security attributes
0, // use default stack size
(LPTHREAD_START_ROUTINE) ThreadFunc, // thread function
NULL, // no thread function argument
0, // use default creation flags
&IDThread); // returns thread identifier
// Check the return value for success.
if (hThread[i] == NULL)
ErrorExit("CreateThread error\n");
}
WaitForMultipleObjects(THREADCOUNT, hThread, TRUE, INFINITE);
FreeLibrary(hm);
return 0;
}
VOID ErrorExit (LPSTR lpszMessage)
{
fprintf(stderr, "%s\n", lpszMessage);
ExitProcess(0);
}
Kapcsolódó témakörök