1,线程概述
线程是程序汇中独立的指令流。线程有一个优先级,实际上正在处理的程序的位置计数器,一个存储其局部变量的栈。每个线程都有自己的栈。但应用程序的内存和堆由一个进程的所有线程共享。
进程包含资源,如windows句柄,文件句柄或其他内核对象。每个进程都分配了虚拟内存。一个进程至少包含一个线程。操作系统会调度线程。
总结:
同步代码区域(代码块):lock, monitor, spinlock,
mutex,waithandle,semaphore,eventwaithandle,autorestevent/manualresetevent.
barrier,
readwriterlock(slim)
多线程变量同步:interlocked,
进程间同步:
mutex, semaphore,
2,异步委托:
创建线程的一种简单方式是定义一个委托,并异步调用它。委托时方法类型安全的引用。delegate类还支持异步调用委托,在后头创建一个执行任务的线程。
委托使用线程池来完成异步调用。
public
delegate int takesawhiledelegate(int data, int ms);
2.1投票:
iasyncresult
ar=al.begininvoke(1,3000, null, null);
int
result=dl.endinvoke(ar);
2.2 等待句柄 (waithandle)
投票(ar.iscompleted)
或者等待句柄(ar.asyncwaithandle.waitone(50, false)
2.3 异步回调 (dl.begininvoke(1,3000, takesawhilecompleted, dl)
)
传入一个回调函数委托,来异步执行。
回调方法
3,thread类
3.1
给线程传递数据
1,使用带parameterizedthreadstart委托参数的thread构造函数。2,创建自定义类,把线程的方法定位实例方法,这样就可以初始化实例的数据,之后启动线程。
3.2
后台线程:
只要有一个前台线程在运行,应用程序的进程就在运行。如果多个前台线程在运行,而main()方法结束了,应用程序的进程依然是激活的,直到所有前台线程完成其任务为止。
前台线程示例
3.3 线程的优先级
4 线程池
5,任务
5.1 启动任务:
启动任务代码
5.2 连续的任务
task t1=new task(doonfirst);
task
t2=t1.continuewith(doonsecond);
5.3任务层次结构
6 parallel
类
parallel.for
parallel.foreach()
parallel.invoke(fun1,fun2);
parallel.invoke code
7. 取消架构
8, 线程问题: 争用条件和死锁
8.1 争用条件:
死锁演示代码
9, 同步
9.1 lock
语句
栈是线程独立的,但不是私有的。所有线程的栈内所有内容,都可以被其他线程访问。
为什么不用 lock(this)
?
因为这通常超出我们的控制,因为其他人也有可能lock这个对象。一个私有的对象是更好的选择。避免lock一个公开类型,或者超出你代码的控制的实例。
tips:可以提供线程安全的原子操作。
线程不安全-问题代码
9.2
interlocked类
interlock类用于使变量的简单语句原子化,线程安全方式递增、递减、交换和读取。i++不是线程安全的(包含3个操作:从内存获取、递增1、存储回内存,这些操作都可以被线程调度器打断)。
9.3 monitor类
lock语句由编译器解释为monitor类: moniter.enter(obj) ;
monitor.exit(obj);
monitor类的一个优点:可以添加一个等待被锁定的超市值。monitor.tryenter(lockobj,500,ref
locktoken);
monitor.tryenter
9.4
spinlock结构
适合于有大量的锁定,而且锁定的时间非常短。用法非常接近于monitor类。获得锁使用enter()或者tryenter(),释放锁使用exit()方法。小心spinlock的传送,因为是结构,所以会复制。
9.5 waithandle基类
delegate begininvoke()
用waithandle.waitone(50,false)来bolck当前线程,
waithandle是一个抽象基类,用于等待一个信号量的设置。可以等待不同的信号,因为waithandle是一个基类,可以派生一些类。
asyncwaithandle
waitone() 等待一个,waitall()等待多个对象,waitany等待多个对象的一个。waitall和waitany是静态方法。
waithandle基类有一个safewaithandle属性,其中可以将本机句柄赋予一个操作系统资源,并等待该句柄。
mutex、eventwaithandle
和 semaphore类继承自waithandle基类。所以可以等到使用它们。
9.6 mutex类
mutex(mutual
exclusion,互斥)是.net
framework中提供多个集成同步访问的一个类。它非常类似于monitor,只有一个线程能拥有锁定。只有一个线程能获得互斥锁定,访问受互斥访问的同步代码区域。
在mutex类的构造函数中,可以指定互斥是否最初由主调线程拥有。定义互斥的名称,获得互斥是否存在的信息。
系统能识别有名称的mutex
mutex
9.7
semaphore类
信号量非常类似于互斥,其区别是多个线程使用。信号量是一种技术的互斥锁定。使用信号量可以定义同时访问旗语锁定保护的资源的线程个数。
semaphore类:可以命名,使用系统范围内的资源,允许不同进程间同步。
semaphore(多线程&跨进程同步)
semaphoreslim类是对于较短等待时间进行了优化的轻型版本,不能跨进程。不能命名,不使用内核信号量,不能跨进程。
semaphoreslim
9.8 event类
事件是另一个系统范围内的资源同步方法。为了从托管代码中使用系统事件,.net
framework提供了manualresetevent、autoresetevent、manualreseteventslim和countdownevent类。
manualresetevent
把任务分支到多个任务中,并在以后合并结果,使用新的countdownevent类很有用。
不需要位每个任务创建一个单独的事件对象,而只需要创建一个事件对象。
var mevents = new manualreseteventslim[taskcount];
// var
cevent = new countdownevent(taskcount);
var waithandles = new waithandle[taskcount];
var
calcs = new calculator[taskcount];
int index = waithandle.waitany(waithandles);//wait
//tasks
mevent.set();//all thread set;
//continue
countdownevent
9.9 barrier 类
适合于工作有多个任务分支且以后又需要合并工作的情况。
var barrier = new barrier(numbertasks +
1);
barrier.signalandwait();//wait
barrier.removeparticipant();//2
left
barrier.removeparticipant();//1 left
//continue.
9.10
readwriterlockslim类
允许多个读取器。同时只有一个写入器工作,此时读取器不能工作。
readwriterlockslim
10 timer类