c#的多线程机制初探(4)_c#教程

2008-02-23 05:43:47来源:互联网 阅读 ()

新老客户大回馈,云服务器低至5折

expression代表您希望跟踪的对象,通常是对象引用。一般地,假如您想保护一个类的实例,您能够使用this;假如您希望保护一个静态变量(如互斥代码段在一个静态方法内部),一般使用类名就能够了。而statement_block就是互斥段的代码,这段代码在一个时刻内只可能被一个线程执行。

  下面是个使用lock关键字的典型例子,我将在注释里向大家说明lock关键字的用法和用途:

??//lock.cs
??using System;
??using System.Threading;

??internal class Account
??{
????int balance;
????Random r = new Random();
????internal Account(int initial)
????{
??????balance = initial;
????}

????internal int Withdraw(int amount)
????{
??????if (balance < 0)
??????{
????????//假如balance小于0则抛出异常
????????throw new Exception("Negative Balance");
??????}
??????//下面的代码确保在当前线程修改balance的值完成之前
??????//不会有其他线程也执行这段代码来修改balance的值
??????//因此,balance的值是不可能小于0的
??????lock (this)
??????{
????????Console.WriteLine("Current Thread:" Thread.CurrentThread.Name);
????????//假如没有lock关键字的保护,那么可能在执行完if的条件判断之后
????????//另外一个线程却执行了balance=balance-amount修改了balance的值
????????//而这个修改对这个线程是不可见的,所以可能导致这时if的条件已不成立了
????????//但是,这个线程却继续执行balance=balance-amount,所以导致balance可能小于0
????????if (balance >= amount)
????????{
??????????Thread.Sleep(5);
??????????balance = balance - amount;
??????????return amount;
????????}
????????else
????????{
??????????return 0; // transaction rejected
????????}
??????}
????}
????internal void DoTransactions()
????{
??????for (int i = 0; i < 100; i )
????????Withdraw(r.Next(-50, 100));
????}
??}

??internal class Test
??{
????static internal Thread[] threads = new Thread[10];
????public static void Main()
????{
??????Account acc = new Account (0);
??????for (int i = 0; i < 10; i )
??????{
????????Thread t = new Thread(new ThreadStart(acc.DoTransactions));
????????threads[i] = t;
??????}
??????for (int i = 0; i < 10; i )
????????threads[i].Name=i.ToString();
??????for (int i = 0; i < 10; i )
????????threads[i].Start();
??????Console.ReadLine();
????}
??}

而多线程公用一个对象时,也会出现和公用代码类似的问题,这种问题就不应该使用lock关键字了,这里需要用到System.Threading中的一个类Monitor,我们能够称之为监控器,Monitor提供了使线程共享资源的方案。

  Monitor类能够锁定一个对象,一个线程只有得到这把锁才能够对该对象进行操作。对象锁机制确保了在可能引起混乱的情况下一个时刻只有一个线程能够访问这个对象。Monitor必须和一个具体的对象相关联,但是由于他是个静态的类,所以不能使用他来定义对象,而且他的任何方法都是静态的,不能使用对象来引用。下面代码说明了使用Monitor锁定一个对象的情形:

??......
??Queue oQueue=new Queue();
??......
??Monitor.Enter(oQueue);
??......//现在oQueue对象只能被当前线程操纵了
??Monitor.Exit(oQueue);//释放锁

??如上所示,当一个线程调用Monitor.Enter()方法锁定一个对象时,这个对象就归他任何了,其他线程想要访问这个对象,只有等待他使用Monitor.Exit()方法释放锁。为了确保线程最终都能释放锁,您能够把Monitor.Exit()方法写在try-catch-finally结构中的finally代码块里。对于任何一个被Monitor锁定的对象,内存中都保存着和他相关的一些信息,其一是现在持有锁的线程的引用,其二是个预备队列,队列中保存了已准备好获取锁的线程,其三是个等待队列,队列中保存着当前正在等待这个对象状态改变的队列的引用。当拥有对象锁的线程准备释放锁时,他使用Monitor.Pulse()方法通知等待队列中的第一个线程,于是该线程被转移到预备队列中,当对象锁被释放时,在预备队列中的线程能够立即获得对象锁。

??下面是个展示如何使用lock关键字和Monitor类来实现线程的同步和通讯的例子,也是个典型的生产者和消费者问题。这个例程中,生产者线程和消费者线程是交替进行的,生产者写入一个数,消费者立即读取并且显示,我将在注释中介绍该程式的精要所在。用到的系统命名空间如下:

??using System;
??using System.Threading


标签:

版权申明:本站文章部分自网络,如有侵权,请联系:west999com@outlook.com
特别注意:本站所有转载文章言论不代表本站观点,本站所提供的摄影照片,插画,设计作品,如需使用,请与原作者联系,版权归原作者所有

上一篇: c#中调用windows api的要点_c#应用

下一篇: c#的多线程机制初探(3)_c#教程