1.Thread
1.1 Thread生命周期
1.2 Thread本地存储
本地存储槽
Local Store Slot(本地存储槽):存储的信息只对该线程有用,这叫做线程本地化存储
//1.给所有线程分配一个(未命名)数据槽。 存放数据
var slot = Thread.AllocateDataSlot();
Thread.SetData(slot, "hello world");
//2.给所有线程分配一个(aaa)数据槽。 存放数据
var slotaaa = Thread.AllocateNamedDataSlot("aaa");
Thread.SetData(slotaaa, "hello world aaa");
var slotObj = Thread.GetData(slot);
var slotObjaaa = Thread.GetData(slotaaa);
Console.WriteLine(slotObj);
Console.WriteLine(slotObjaaa);
//消除进程与槽位
Thread.FreeNamedDataSlot("aaa");
ThreadStatic
性能提升:
[ThreadStatic]
static string username = string.Empty;
static void Main(string[] args)
{
username = "hello world!!!";
var t = new Thread(() =>
{
Console.WriteLine("当前工作线程:{0}", username);
});
t.Start();
Console.WriteLine("主线程:{0}", username);
Console.Read();
}
ThreadLocal
ThreadLocal<string> local = new ThreadLocal<string>();
local.Value = "hello world!!!";
var t = new Thread(() =>
{
Console.WriteLine("当前工作线程:{0}", local.Value);
});
t.Start();
Console.WriteLine("主线程:{0}", local.Value);
1.3 认识MemoryBarrier
2个线程同时操作一个变量时,这个变量可能加载到Cpu Cache中。这时,就使用到MemoryBarrier
。
例子:因为Release中做了一些代码和缓存的优化。。。 比如说将一些数据从memory中读取到cpu高速缓存中。
static void Main(string[] args)
{
var isStop = false;
var t = new Thread(() =>
{
var isSuccess = false;
while (!isStop)
{
Thread.MemoryBarrier(); //及时从cpu cache中更新到 memor
isSuccess = !isSuccess;
}
});
t.Start();
Thread.Sleep(1000);
isStop = true;
t.Join();
Console.WriteLine("主线程执行结束!");
Console.ReadLine();
}
在此方法之前的内存写入都要及时从cpu cache中更新到 memory。
在此方法之后的内存读取都要从memory中读取,而不是cpu cache。
类似的功能还有:
var isStop = 0;
var t = new Thread(() =>
{
var isSuccess = false;
while (isStop == 0)
{
Thread.VolatileRead(ref isStop);
isSuccess = !isSuccess;
}
});
1.4ThreadPool 线程池
使用线程池的线程,要调用静态方法 ThreadPool.QueueUserWorkItem
,以指定线程要调用的方法。该静态方法有两种:
public static bool QueueUserWorkItem(WaitCallback callBack);
public static bool QueueUserWorkItem(WaitCallback callBack, object state);
这两个方法用于向线程池队列添加一个工作项(work item)以及一个可选的状态数据。
工作项是指一个由 callback 参数标识的委托对象,被委托对象包装的回调方法由线程池来执行。
传入的回调方法匹配 System.Threading.WaitCallback
委托类型
private void button2_Click(object sender, EventArgs e)
{
Console.WriteLine("主线程ID={0}", Thread.CurrentThread.ManagedThreadId);
ThreadPool.QueueUserWorkItem(CallbackWorkItem);
ThreadPool.QueueUserWorkItem(CallbackWorkItem, "work");
Thread.Sleep(3000);
Console.WriteLine("主线程退出");
//线程池线程ID = 5
//主线程ID = 1
//线程池开始执行
//线程池开始执行
//线程池线程ID = 6
//线程池线程ID = 3 传入的参数为 work
//主线程退出
}
private static void CallbackWorkItem(object state)
{
Console.WriteLine("线程池开始执行");
if (state != null)
{
Console.WriteLine("线程池线程ID = {0} 传入的参数为 {1}", Thread.CurrentThread.ManagedThreadId, state.ToString());
}
else
{
Console.WriteLine("线程池线程ID ={0}", Thread.CurrentThread.ManagedThreadId);
}
}
工作者线程与I/O线程
CLR线程池分为工作者线程(workerThreads)与I/O线程 (completionPortThreads) 两种,
工作者线程是主要用作管理CLR内部对象的运作,I/O(Input/Output) 线程顾名思义是用于与外部系统交换信息.
I/O 线程是.NET专为访问外部资源所设置的一种线程,因为访问外部资源常常要受到外界因素的影响,为了防止让主线程受影响而长期处于阻塞状态,.NET为多个I/O操作都建立起了异步方法,例如:FileStream、TCP/IP、WebRequest、WebService等等,而且每个异步方法的使用方式都非常类似,都是以BeginXXX为开始,以EndXXX结束