Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
Bagian ini menunjukkan penggunaan fungsi titik masuk DLL untuk menyiapkan indeks penyimpanan lokal utas (TLS) untuk menyediakan penyimpanan privat untuk setiap utas proses multithread.
Indeks TLS disimpan dalam variabel global, membuatnya tersedia untuk semua fungsi DLL. Contoh ini mengasumsikan bahwa data global DLL tidak dibagikan, karena indeks TLS belum tentu sama untuk setiap proses yang memuat DLL.
Fungsi titik entri menggunakan fungsiTlsAlloc untuk mengalokasikan indeks TLS setiap kali proses memuat DLL. Setiap utas kemudian dapat menggunakan indeks ini untuk menyimpan pointer ke blok memorinya sendiri.
Saat fungsi titik entri dipanggil dengan nilai DLL_PROCESS_ATTACH, kode melakukan tindakan berikut:
- Menggunakan fungsiTlsAlloc untuk mengalokasikan indeks TLS.
- Mengalokasikan sebuah blok memori untuk digunakan secara eksklusif oleh thread awal dari proses tersebut.
- Menggunakan indeks TLS dalam panggilan ke fungsi TlsSetValue untuk menyimpan alamat blok memori di slot TLS yang terkait dengan indeks.
Setiap kali proses membuat utas baru, fungsi titik entri dipanggil dengan nilai DLL_THREAD_ATTACH. Fungsi titik masuk kemudian mengalokasikan blok memori untuk utas baru dan menyimpan penunjuknya dengan menggunakan indeks TLS.
Saat fungsi memerlukan akses ke data yang terkait dengan indeks TLS, tentukan indeks dalam panggilan ke fungsi TlsGetValue. Ini mengakses isi slot TLS untuk utas yang sedang dipanggil, yang merupakan penunjuk ke blok memori untuk data. Ketika sebuah proses menggunakan penautan waktu muat dengan DLL ini, fungsi titik masuk sudah memadai untuk pengelolaan penyimpanan lokal utas. Masalah dapat terjadi dengan proses yang menggunakan penautan run-time karena fungsi titik awal tidak dipanggil untuk utas yang ada sebelum fungsi LoadLibrary dipanggil, sehingga memori TLS tidak dialokasikan untuk utas-utas ini. Contoh ini memecahkan masalah ini dengan memeriksa nilai yang dikembalikan oleh fungsi TlsGetValue dan mengalokasikan memori jika nilai menunjukkan bahwa slot TLS untuk utas ini belum diatur.
Ketika setiap utas tidak perlu lagi menggunakan indeks TLS, setiap utas harus membebaskan memori yang pointer-nya disimpan di slot TLS. Ketika semua utas telah selesai menggunakan indeks TLS, gunakan fungsi TlsFree untuk merilis indeks.
Ketika thread dihentikan, fungsi titik awal dipanggil dengan nilai DLL_THREAD_DETACH dan memori untuk thread tersebut dibebaskan. Ketika sebuah proses berakhir, fungsi titik masuk dipanggil dengan nilai DLL_PROCESS_DETACH dan memori yang dirujuk oleh pointer dalam indeks TLS dibebaskan.
// 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
Kode berikut menunjukkan penggunaan fungsi DLL yang ditentukan dalam contoh sebelumnya.
#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);
}
Topik terkait
-
Menggunakan Penyimpanan Lokal Utas