C21、线程本地存储(TLS)

来源:互联网 发布:软件需求分析面试 编辑:程序博客网 时间:2024/06/06 00:55

一、动态TLS

a)         DWORD TlsAlloc();

u       该函数使系统对进程中的位标志进行扫描,找出一个FREE标志,并转换为INUSE,返回标志的索引。如果找不到FREE标志,返回TLS_OUT_OF_INDEXES(0XFFFFFFFF)

u       而且,如果这个索引位置已经分配了内存,会删除内存,并置0

b)        将值放入本线程的数组中(不能放入其他线程的数组):

BOOL TlsSetValue(              // 调用成功,返回TRUE

DWORD dwTlsIndex,   // TlsAlloc返回值

PVOID pvTlsValue);   // 任意值

c)        从线程的数组中检索一个值(仅调用线程的数组):

PVOID TlsGetValue(DWORD dwTlsIndex);

d)        当所有线程不再需要保留TLS时隙的位置时,释放:

BOOL TlsFreeDWORD dwTlsIndex);

进程的位标志数组将INUSE设置为FREE

二、使用动态TLS

通常,DLL在使用DLL_PROCESS_ATTACH标志调用DllMain时,调用TlsAlloc;用DLL_PROCESS_DETACH调用DllMain时调用TlsFree。例:

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

DWORD g_dwTlsIndex ;       // 假设他正确使用TlsAlloc初始化

……

void MyFunc(PSOMESTRUCT pSomeStruct){

if(pSomeStruct != NULL){    // 设置值?

if(TlsGetValue(g_dwTlsIndex) == NULL){     // 查看是否已分配了空间保存数据?

  // 没有分配空间

      TlsSetValue(g_dwTlsIndex, HeapAlloc(GetProcessHeap(), 0, sizeof(*pSomeStruct));

    }

    // 此时,已经肯定分配了存储空间。保存数据

    memcpy(TlsGetValue(g_dwTlsIndex), pSomeStruct, sizeof(*pSomeStruct));

} else {    // 取回值

    // 获取保存数据的地址

    pSomeStruct = (PSOMESTRUCT)TlsGetValue(g_dwTlsIndex);

    ……    // 使用数据

}

}

//////////////////////////////////////////////////// End of xample ///////////////////////////////////////////////////////

三、静态TLS:(更容易使用,不需调用任何函数)

比如,你需要每个线程的起始时间:

__declspec(thread) DWORD gt_dwStartTime = 0;

u       __declspec(thread)使编译时,把变量放入自己的节中(.tls节)。变量必须为函数内(外)的全局或静态变量(不能为局部变量)。

u       系统在程序或DLL加载时,查看.tls节,并为节内的数据分配内存;卸载时回收。

u       但是,运行期显示加载的DLL没有进行初始化。

u       这样会使程序变大,系统负担加重。