书上说:
当一个线程被创建时,windows就会在进程地址空间中为该线程分配一个长度为TLS_MINIMUM_AVAILABLE的数组,数组成员的值都被初始化为0。在内部,系统将此数组与该线程关联起来,保证只能在该线程中访问此数组中的数据。每个线程都有自己的数组,数组成员可以储存任何数据。
一个线程只能改变自己线程数组中的成员的值,而没有办法为另一个线程设置TLS值。
TlsSetValue和TlsGetValue分别用于设置和取得线程数组中特定成员的值,而他们使用的索引就是TlsAlloc函数的返回值。例如,TlsAlloc返回3,那就说明索引3被此进程中的每一个正在运行的和以后要被创建的线程保存起来,用以访问各自线程数组中对应的成员的值。
我想问的是既然一个线程只能访问自己的线程数组,而上面又说索引3被很多线程保存,多个线程怎么根据一个索引访问不同的值?是怎么实现的?一个索引怎么可以指向不同的值?
还有没一个进程唯一的维数组和,线程的线程数组长度为什么是一样的。下面是书上的例子:
//利用TLS跟踪线程的运行时间
#include<stdio.h>
#include<windows.h>
#include<process.h>
DWORD g_tlsUsedTime;
void InitStartTime();
DWORD GetUsedTime();
UINT _stdcall ThreadFunc(LPVOID)
{
int i;
//初始化开始时间
InitStartTime();
//模拟长时间工作
i=1000*1000;
while(i--){}
//打印出本线程运行的时间
printf("Thise thread is coming to end. Thread ID:%-5d,Used Time:%d\n",::GetCurrentThreadId(),GetUsedTime());
getchar();
return 0;
}
int main()
{
UINT uId;
int i;
HANDLE h[10];
//通过在进程位数组中申请一个索引,初始化线程运行时间记录系统
g_tlsUsedTime=::TlsAlloc(); //这里只有一个索引,给下面十个线程共用还是我理解错了 ?
//令十个线程同时运行,并等待它们各自的输出结果
for(i=0;i<10;i++)
{ h[i]=(HANDLE)::_beginthreadex(NULL,0,ThreadFunc,NULL,0,&uId);}
for(i=0;i<10;i++)
{ ::WaitForSingleObject(h[i],INFINITE);
::CloseHandle(h[i]);}
//通过释放线程局部储存索引,释放释放时间记录系统占用的资源
::TlsFree(g_tlsUsedTime);
return 0;
}
//初始化线程的开始时间
void InitStartTime()
{
DWORD dwStart=::GetTickCount();
::TlsSetValue(g_tlsUsedTime,(LPVOID)dwStart);
}
//取得一个线程已运行的时间
DWORD GetUsedTime()
{
//获得当前时间,返回当前时间和线程创建时间的差值
DWORD dwElapsed=::GetTickCount();
dwElapsed=dwElapsed-(DWORD)::TlsGetValue(g_tlsUsedTime);
return dwElapsed;
}
位数组和线程数组到底是什么关系?
当一个线程被创建时,windows就会在进程地址空间中为该线程分配一个长度为TLS_MINIMUM_AVAILABLE的数组,数组成员的值都被初始化为0。在内部,系统将此数组与该线程关联起来,保证只能在该线程中访问此数组中的数据。每个线程都有自己的数组,数组成员可以储存任何数据。
一个线程只能改变自己线程数组中的成员的值,而没有办法为另一个线程设置TLS值。
TlsSetValue和TlsGetValue分别用于设置和取得线程数组中特定成员的值,而他们使用的索引就是TlsAlloc函数的返回值。例如,TlsAlloc返回3,那就说明索引3被此进程中的每一个正在运行的和以后要被创建的线程保存起来,用以访问各自线程数组中对应的成员的值。
我想问的是既然一个线程只能访问自己的线程数组,而上面又说索引3被很多线程保存,多个线程怎么根据一个索引访问不同的值?是怎么实现的?一个索引怎么可以指向不同的值?
还有没一个进程唯一的维数组和,线程的线程数组长度为什么是一样的。下面是书上的例子:
//利用TLS跟踪线程的运行时间
#include<stdio.h>
#include<windows.h>
#include<process.h>
DWORD g_tlsUsedTime;
void InitStartTime();
DWORD GetUsedTime();
UINT _stdcall ThreadFunc(LPVOID)
{
int i;
//初始化开始时间
InitStartTime();
//模拟长时间工作
i=1000*1000;
while(i--){}
//打印出本线程运行的时间
printf("Thise thread is coming to end. Thread ID:%-5d,Used Time:%d\n",::GetCurrentThreadId(),GetUsedTime());
getchar();
return 0;
}
int main()
{
UINT uId;
int i;
HANDLE h[10];
//通过在进程位数组中申请一个索引,初始化线程运行时间记录系统
g_tlsUsedTime=::TlsAlloc(); //这里只有一个索引,给下面十个线程共用还是我理解错了 ?
//令十个线程同时运行,并等待它们各自的输出结果
for(i=0;i<10;i++)
{ h[i]=(HANDLE)::_beginthreadex(NULL,0,ThreadFunc,NULL,0,&uId);}
for(i=0;i<10;i++)
{ ::WaitForSingleObject(h[i],INFINITE);
::CloseHandle(h[i]);}
//通过释放线程局部储存索引,释放释放时间记录系统占用的资源
::TlsFree(g_tlsUsedTime);
return 0;
}
//初始化线程的开始时间
void InitStartTime()
{
DWORD dwStart=::GetTickCount();
::TlsSetValue(g_tlsUsedTime,(LPVOID)dwStart);
}
//取得一个线程已运行的时间
DWORD GetUsedTime()
{
//获得当前时间,返回当前时间和线程创建时间的差值
DWORD dwElapsed=::GetTickCount();
dwElapsed=dwElapsed-(DWORD)::TlsGetValue(g_tlsUsedTime);
return dwElapsed;
}
位数组和线程数组到底是什么关系?
堆栈中定义的局部变量,对多线程是安全的,因为不同的线程有自己的堆栈。而通常定义的全局变量,所有线程都可以作读写访问,这样它就不是线程安全的,为安全就有必要加锁互斥访问。而何为线程局部存储(TLS),简单的说,就是一个变量(通常是指针,指向具体的类型),每个线程都有一个副本,而在程序中可以按照相同的方式来访问,(比如使用相同的变量名,又或者都调用TlsGetValue),既然是都有副本,自然线程中互不影响。打个比方,就如同一个人,被克隆出三个,其中一个被砍了一刀,其它两人都不会受伤。