C#线程同步详细分析
在向大家详细介绍C#线程同步之前,首先让大家了解下C#线程的中止,然后全面介绍C#线程同步。
C#线程的中止
由于能够在没有任何征兆的情况下使运行的程序进入一种混乱的状态,Java中的Thread.stop受到了普遍的反对。根据所调用的stop()方法,一个未经检查的java.lang.ThreadDeath错误将会破坏正在运行着的程序的栈,随着它的不断运行,能够解除任何被锁定的对象。由于这些锁被不分青红皂白地被打开,由它们所保护的数据就非常可能陷入混乱状态中。
根据当前的Java文档,推荐的中止一个线程的方法是让运行的线程检查一个由其他的线程能够改变的变量,该变量代表一个“死亡时间”条件。下面的程序就演示了这种方法。
// 条件变量 private boolean timeToDie = false; // 在每次迭代中对条件变量进行检查。 class StoppableRunnable extends Runnable { public void run() { while( !timeToDie ) { // 进行相应的操作 } } }
上述的讨论对C#中的Abort方法也适合。根据调用的Abort方法,令人捉摸不定的System.Threading.ThreadAbortException可能会破坏线程的栈,它可能释放线程保持的一些变量,使处于保护状态中的数据结构出现不可预测的错误。我建议使用与上面所示的相似的方法来通知一个应该死亡的线程。
C#线程同步
从概念上来看,线程非常易于理解,实际上,由于他们可能交互地对同一数据结构进行操作,因此它们成为了令编程人员头疼的一种东西。以本文开始的 ThreadingExample为例,当它运行时,会在控制台上输出多种不同的结果。从 1 2 3 4 5 1 2 3 4 5到 1 1 2 2 3 3 4 4 5 5或 1 2 1 2 3 3 4 5 4 5在内的各种情况都是可能出现的,输出结果可能与操作系统的线程调度方式之间的差别有关。有时,需要确保只有一个线程能够访问一个给定的数据结构,以保证数据结构的稳定,这也是我们需要C#线程同步机制的原因所在。
为了保证数据结构的稳定,我们必须通过使用“锁”来调整二个线程的操作顺序。二种语言都通过对引用的对象申请一个“锁”,一旦一段程序获得该“锁”的控制权后,就可以保证只有它获得了这个“锁”,能够对该对象进行操作。同样,利用这种锁,一个线程可以一直处于等待状态,直到有能够唤醒它信号通过变量传来为止。