.NET 线程学习笔记二

来源:互联网 发布:淘宝自动秒杀软件 编辑:程序博客网 时间:2024/04/27 23:50

  

互斥锁:

    //互斥锁是一个互斥的同步对象,这意味着在同一个时间有且仅有一个线程可以获取它。互斥锁适用于下列情况:

    //一个共享资源每次只能被一个线程使用。例如:考虑一个由多个进程共享的日志文件,任意时刻只能有一个进程对
    //该文件执行写入操作。互斥锁是解决此类问题的最佳同步工具。
    //互斥锁由System.Threading.Mutex类支持。该类有多个构造函数,其中最常用的两个是:
    //publi Mutex()
    //publi Mutex(bool owned)
    //第一个版本创建一个处于未获取状态的互斥锁。
    //在第二个版本中,如果owned为true,互斥锁的初始状态就是被主调线程所获取,否则处于未获取状态。
    //要获取一个互斥锁,应当调用互斥锁上的WaitOne()方法。该方法继承于System.Threading.WaitHandle
    //下面是它的最简单形式:
    //public bool WaitOne();
    //它将处于等待状态知道所调用的互斥锁可以被获取。因此该方法将阻塞主线程直到指定的互斥锁可用。该方法总是返回true.
    //如果代码不再需要拥有互斥锁,可以调用下面的ReleaseMutex()方法来释放它:
    //public void ReleaseMutex();
    //在互斥锁上调用该方法将使得互斥锁被释放,从而允许该互斥锁被另一个线程所获取。
    //要使用互斥锁来同步对共享资源的访问,需要使用WaitOne()和ReleaseMutex如下面的代码所示。

    //Mutex myMtx = new Mutex();
    //myMtx.WaitOne();
    //myMtx.ReleaseMutex();

    //在调用WaitOne()方法是,线程的执行将挂起直到获取互斥锁。在调用ReleaseMutex方法时,互斥锁将被释放,从而另一个线程可以获取它。
    //通过这种方法,共享资源可以被限制为每次只允许一个线程访问。

  
public class ShardRes    {        public static int Count = 0;        public static Mutex Mtx = new Mutex();    }    class IncThread    {        int num;        public Thread Thrd;        public IncThread(string name, int n)        {            Thrd = new Thread(new ThreadStart(this.Run));            num = n;            Thrd.Name = name;            Thrd.Start();        }        void Run()        {            Console.WriteLine(Thrd.Name + " is waiting for the mutex");            ShardRes.Mtx.WaitOne();            Console.WriteLine(Thrd.Name + " acquires the mutex.");            do            {                Thread.Sleep(500);                ShardRes.Count++;                Console.WriteLine("In " + Thrd.Name + ",ShardRes.Count is" + ShardRes.Count);                num--;            }            while (num > 0);            Console.WriteLine(Thrd.Name + " releases the mutex.");            ShardRes.Mtx.ReleaseMutex();        }    }    public class DecThread    {        int num;        public Thread Thrd;        public DecThread(string name, int n)        {            Thrd = new Thread(new ThreadStart(this.Run));            num = n;            Thrd.Name = name;            Thrd.Start();        }        public void Run()        {            Console.WriteLine(Thrd.Name + " is waiting for the mutex");            ShardRes.Mtx.WaitOne();            do            {                Thread.Sleep(500);                ShardRes.Count--;                Console.WriteLine("In " + Thrd.Name + ",SharedRes.count is " + ShardRes.Count);                num--;            } while (num > 0);            Console.WriteLine(Thrd.Name + " releases the mutex.");            ShardRes.Mtx.ReleaseMutex();        }    }    class ThreadFive    {        public static void Main(string[] arg)        {            Console.WriteLine("ok");            IncThread mt1 = new IncThread("Increment Thread", 5);            Thread.Sleep(1);            DecThread mt2 = new DecThread("Decrement Thread", 5);            mt1.Thrd.Join();            mt2.Thrd.Join();            Console.Read();        }    }

信号量:

 //信号量类似于互斥锁,但它可以允许多个线程同时访问一个共享资源。因此在同步一个资源集合的时候,信号量就显得非常有用。
    //信号量通过一个计数器来控制对共享资源的访问。如果计数器大于0,那么就iu允许访问。如果计数器等于0,就拒绝访问。计数
    //器累计的是“许可证”的个数。因此,为了访问某个资源,线程将阻塞直到得到一个许可证。

    //信号量特别使用于下列情况:一个由“组(group)”或者"池(pool)"构成的共享资源。例如一个网络连接的集合,其中每一个连接
    //都可以用于通信,这就是一个资源池。需要网络连接的线程并不关心它获取的是哪一个网络连接。在这种情况下,信号量提供了
    //一种方便的机制来管理对连接的访问。
    //信号量是由System.Threading.Semaphore实现的。它有多个构造函数,最简单形式为:
    //public Semaphore(int initial,int max)
    //其中,initial指定了信号量许可证计数器的初始值,它指定可用的许可证数目。计数器的最大值在max中传递。max地表了信号量
    //最多拥有的许可证数目.initial的值指定了初始情况下有多少个许可证可用。


    //获取信号量使用  WaitOne()
    //不再需要使用信号量使用Release()方法释放。

    //注意:
    //线程在调用Release()之前可以多次调用WaitOne().但是,在释放许可证之前,WaitOne()的调用次数必须和Release()的调用次数一致。
    //或者,也可以调用Release(int)形式,传入WaitOne()的调用次数。

    class ThreadSix    {        public Thread Thr;        static Semaphore sem = new Semaphore(2, 2);        public ThreadSix(string name)        {            Thr = new Thread(this.Run);            Thr.Name = name;            Thr.Start();        }        public void Run()        {            Console.WriteLine(Thr.Name + " is waiting for permit");            sem.WaitOne();            Console.WriteLine(Thr.Name + " is acquires for permit");            for (char ch = 'A'; ch < 'D'; ch++)            {                Console.WriteLine(Thr.Name + " : " + ch + " ");                Thread.Sleep(500);            }            Console.WriteLine(Thr.Name + " releases a permit.");            sem.Release();        }    }    public class SemaphoreDemo    {        static void Main(string[] arg)        {            ThreadSix t1 = new ThreadSix("one");            ThreadSix t2 = new ThreadSix("two");            ThreadSix t3 = new ThreadSix("three");            t1.Thr.Join();            t2.Thr.Join();            t3.Thr.Join();            Console.Read();        }    }

  //使用事件实现同步。
    //同步事件有两种类型:ManualResetEvent(手工重置) AutoResetEvent(自动重置)
    //事件处理非常简单。对于ManualResetEvent,其处理过程处理如下:等待某个事件
    //的线程简单的代表该事件的事件对象上调用WaitOne();如果事件对象处于已发出
    //信号状态,WaitOne将立即返回。它将挂起主调线程直到事件发出信号。在另一个线程执行事件之后,该线程通过调用
    //Set()来把事件对象置于已发出信号状态,对WaitOne()的调用将返回,并且第一个线程恢复执行。
    //调用Reset()将该事件重置为未发出信号状态。
    public class ThreadSeven    {        public Thread Thrd;        ManualResetEvent mre;        public ThreadSeven(string name, ManualResetEvent evt)        {            Thrd = new Thread(this.Run);            Thrd.Name = name;            mre = evt;            Thrd.Start();        }        public void Run()        {            Console.WriteLine("Inside thread " + Thrd.Name);            for (int i = 0; i < 5; i++)            {                Console.WriteLine(Thrd.Name);                Thread.Sleep(500);            }            Console.WriteLine(Thrd.Name + " Done!");           mre.Set();        }    }    class ManualEventDemo    {        static void Main()        {            ManualResetEvent mre = new ManualResetEvent(false);            ThreadSeven mt1 = new ThreadSeven("Event Thread 1", mre);            Console.WriteLine("Main thread is waiting first event.");            mre.WaitOne();                      Console.WriteLine("Main thread received first event.");            mre.Reset();            mt1 = new ThreadSeven("Event Thread 2", mre);            mre.WaitOne();            Console.WriteLine("Main Thread received second event.");            Console.Read();        }    }