0.thread本身来说就是操作系统的概念
1.空间开销
1)thread的内核结构,其中有osid,context=》cpu寄存器的里面的一些变量
2)thread环境块
Tls【thread本地存储】,exceptionList的信息
windbg下载(需要注意和操作系统的位数一致)
可以达到clr的层面给大家展示底层的知识
举例:
创建一个window项目
namespaceConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Thread t = new Thread(newThreadStart(() =>
{
}));
t.Start();
Console.Read();
}
}
}
编译,然后再debug文件夹中运行
运行截图:
使用windbg查看程序
运行32位的windbg,在菜单中找到File -> Attach to a Process…
然后,需要加载sos和clr包
.loadby sos clr
可以来看一下该程序里面的线程:
执行!threads
可以看到,其中有一个线程死了(DeadThread: 1)
下面进入正题
执行!teb ,执行结果如下:
0:005> !teb
TEB at 0047b000
ExceptionList: 00f5f7c8
StackBase: 00f60000
StackLimit: 00f5c000
SubSystemTib: 00000000
FiberData: 00001e00
ArbitraryUserPointer: 00000000
Self: 0047b000
EnvironmentPointer: 00000000
ClientId: 00000b44 . 00001ef8
RpcHandle: 00000000
TlsStorage: 00000000
PEB Address: 0045d000
LastErrorValue: 0
LastStatusValue: 0
Count Owned Locks: 0
HardErrorMode: 0
其中ExceptionList:存放异常信息,Tls Storage:存放数据(可让数据仅让本线程可见)
上图中可以看到OSID,每个线程都有OSID
3)用户模式堆栈
如平时内存溢出的一个异常【堆栈溢出】
一个线程分配1M的堆栈空间,这个空间存储参数、局部变量等
4)内核模式堆栈
在CLR的线程操作,包括线程同步,大多都是调用底层的win32函数,用户模式堆栈需要传递到内核模式
2.时间上的开销
1)我们的进程启动的时候,会加载很多的dll【包括托管和非托管的】,exe,还有一些资源,元数据。。。
在刚才的启动windbg,附加进程的时候,会加载很多资源
进程启动的时候,为什么没看到应用程序域?
进程启动的时候,默认会有三个应用程序域。System domain, Shared Domain, Domain 1
执行!dumpdomain,来查看当前进程的应用 程序域。
System domain:系统的应用程序域
SharedDomain:是系统Domain创建的,将程序加载到Shared Domain中,如一些基础类型等(int double等)
Domain1:是我们的应用程序Application插件的应用程序域
总结一下,开启一个thread,销毁一个thread,都会通知进程中的dll,attach,detach标志位。
设置这些标志的目的,是通知dll,给thread做准备工作。比如销毁,让这些dll做资源清理。
2)时间片切换开销
4个逻辑处理器,可供4个thread并行执行。如果多于4个thread并发执行,如5个,必然会有1个thread休眠30ms。
3.上面这些就是开启thread带来的开销
4.使用thread需要权衡利弊,是否适合。
For=》 palleral for