Megosztás a következőn keresztül:


Szálhoz kötött tárolás használata a Dynamic-Link könyvtárban

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:

  1. A TLS-index lefoglalásához a TlsAlloc függvényt használja.
  2. Lefoglal egy memóriablokkot, amelyet kizárólag a folyamat kezdeti szála használ.
  3. 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); 
}

Dynamic-Link könyvtáradatok

Szálhelyi tárolás használata