C#中也有函数指针(委托),因此创建起来就可以直接传参给构造函数。。这点比 Java简单。。
第15章 线程
多线程的工作方式
一个处理器在某一时刻只能处理一个任务,如果有一个多处理器系统,理论上可以同时执行多个指令。
Windows操作系统表面上可以同时处理多个任务,这个过程称为抢先式多任 务 处理(pre-emptive multitasking)。
它是指Windows在某个进程中选择一个线程,该线程允许一小段时间(时间片),之后系统就回收控制权,选择下一个被分派了时间片的线程。这种时 间非常短暂,我们可以认为许多事件是同时发生的。
(算法上就是时间片轮 转调度吧……?只是这里还支持优先级……)
线程处理
创建Thread需要一个参数用于指定线程的入口——即线程开始执行的方法。
在C#中就是使用委托。它的签名是:public delegate void ThreadStart()。
由于没有参数,所以必须以其他方式传递信息,例如使用成员字段。
其他常用方法:
- 挂起线程:Suspend()
- 恢复 线程:Resume()
- 中断 线程:Abort()
- 等待 线程终止:Join(),可以指定等待时间。如果过了等待 时间,程序会继续进行。
- 睡 眠:Sleep(),令当前正在运行的线程进入睡眠状态。
注意Suspend()和Abort()方法不会立即作用,需要等待一定时间。
线程挂起时,.NET允许其再执行几个指令,直到.NET认为线程可以安全挂起,以保证垃圾回收器执行正确的操作;
线程中断时,将会抛出一个ThreadAbortException。线程真正终止前将执行相应的finally块,这样就保证清理资源,并有机会确保线程正在处理的数据处于有效的状 态。
线程的优先级:可以在线程Start前定义它的Priority属性为ThreadPriority的一个枚举值。
同步
通过使用关键字lock来 独占对象。
当变量被包装在独占锁中,其他线程就不能访问该变量。Windows会让其他线程处于睡眠状态,直到解锁。
同步问题
死锁:如下就可能造成死锁,在实际应用中要小心在不同 的方法调用中使用不同的锁而 造成死锁。
lock(a) { // do sth.. lock(b) { // do sth.. } } | lock(b) { // do sth.. lock(a) { // do sth.. } } |
竞态:当几个线程试图访问同一个数据,但没有充分考虑 其他线程的执行情况时就会发 生竞态。如:
01.
lock
(a)
02.
{
03.
// part 1: do sth..
04.
// using a
05.
}
06.
07.
// do sth.. <- Current..
08.
09.
lock
(a)
10.
{
11.
// part2: do sth..
12.
// using a
13.
}
若线程A执行到Current位置,线程B执行完part1,则A在part2时就会误读到B在part1中改过的数据。