C# 多线程中的lock,Monitor.pulse(all)&wait

C#线程间的同步常用lock, monitor来实现. 本文分析一下lock与monitor的异同点.


1. 只使用lock.

当进入临界区时 lock(lockObj){ .......  }, 该线程将获得锁.直到临界区退出之后,才会释放. 另一线程才有机会获得锁.如下面代码. 在临界区内的sleep不会释放锁.

辅助线程在临界区外面进行sleep时,此时因为已经释放了锁,所以主线程会借此机会得到锁. 线程的调度与资源的抢占依赖于操作系统的策略.

    class Program
    {
        private static Object lockObj = new Object();
        static void ThreadMain()
        {
            while(true)
            {
                lock (lockObj)
                {
                    Console.WriteLine("not main thread got the lock");
                    Console.WriteLine("not main thread will sleep 10s");
                    Thread.Sleep(10000);
                    //Monitor.Pulse(lockObj);
                    //Monitor.Wait(lockObj);
                    Console.WriteLine("not main thread wait to sleep 15s again");
                    Thread.Sleep(15000);
                    Console.WriteLine("not main thread will go on");
                }
                Console.WriteLine("I want to sleep 20s here");
                Thread.Sleep(20000);
            }


        }
        static void Main(string[] args)
        {
            Thread thread1 = new Thread(new ThreadStart(ThreadMain));
            thread1.Start();
            Console.WriteLine("Main thread");
            while (true)
            {
                lock (lockObj)
                {
                    Console.WriteLine("Main thread got the lock");
                    Console.WriteLine("Main thread will sleep 5s");
                    Thread.Sleep(5000);
                    //Monitor.Pulse(lockObj);
                    //Monitor.Wait(lockObj);
                    Console.WriteLine("Main thread will go on");
                }
            }
        }
    }

程序运行结果:

Main thread
Main thread got the lock
Main thread will sleep 5s
Main thread will go on
not main thread got the lock
not main thread will sleep 10s
not main thread wait to sleep 15s again
not main thread will go on
I want to sleep 20s here
Main thread got the lock
Main thread will sleep 5s
Main thread will go on
Main thread got the lock
Main thread will sleep 5s
Main thread will go on
Main thread got the lock
Main thread will sleep 5s
Main thread will go on
Main thread got the lock
Main thread will sleep 5s
Main thread will go on
Main thread got the lock
Main thread will sleep 5s
Main thread will go on
not main thread got the lock
not main thread will sleep 10s
not main thread wait to sleep 15s again


2. 稍做改动,搭配monitor使用. 进入lock(lockObj){......}仍然是获得锁,但调用Monitor.Pulse(lockObj);会通知另一线程进入随时待命抢锁的状态,而调用Monitor.Wait(lockObj);之后,线程会释放锁(不用等临界区结束),并把自己放入一个休息区,进行等待.直到收到另一线程的Pulse通知后,才进行待命状态.(特别注意,如果线程调用了Monitor.wait方法,则该线程将休息在这里.直到收到另一线程的Pulse通知后,才会待命,才有机会再次获取锁. 若线程获得锁,则会从wait后面的一行代码开始继续执行.临界区执行结束后,虽然线程会释放锁,但另一线程由于在休息区,仍然不会获得锁. 从辅助线程在临界区外的休息,主线程仍然不执行可以看出这一点.之后,辅助线程继续循环,当辅助线程再次调用pulse, wait时,主县城才会获得锁,得到继续执行的机会.

通过pulse与wait,可以实现更灵活的线程的调度,不完全依赖操作系统的策略.


    class Program
    {
        private static Object lockObj = new Object();
        static void ThreadMain()
        {
            while(true)
            {
                lock (lockObj)
                {
                    Console.WriteLine("not main thread got the lock");
                    Console.WriteLine("not main thread will sleep 10s");
                    Thread.Sleep(10000);
                    Monitor.Pulse(lockObj);
                    Monitor.Wait(lockObj);
                    Console.WriteLine("not main thread wait to sleep 15s again");
                    Thread.Sleep(15000);
                    Console.WriteLine("not main thread will go on");
                }
                Console.WriteLine("I want to sleep 20s here");
                Thread.Sleep(20000);
            }


        }
        static void Main(string[] args)
        {
            Thread thread1 = new Thread(new ThreadStart(ThreadMain));
            thread1.Start();
            Console.WriteLine("Main thread");
            while (true)
            {
                lock (lockObj)
                {
                    Console.WriteLine("Main thread got the lock");
                    Console.WriteLine("Main thread will sleep 5s");
                    Thread.Sleep(5000);
                    Monitor.Pulse(lockObj);
                    Monitor.Wait(lockObj);
                    Console.WriteLine("Main thread will go on");
                }
            }
        }
    }


程序运行结果:

Main thread
Main thread got the lock
Main thread will sleep 5s
not main thread got the lock
not main thread will sleep 10s
Main thread will go on
Main thread got the lock
Main thread will sleep 5s
not main thread wait to sleep 15s again
not main thread will go on
I want to sleep 20s here
not main thread got the lock
not main thread will sleep 10s
Main thread will go on
Main thread got the lock
Main thread will sleep 5s
not main thread wait to sleep 15s again
not main thread will go on
I want to sleep 20s here
not main thread got the lock
not main thread will sleep 10s
Main thread will go on
Main thread got the lock
Main thread will sleep 5s
not main thread wait to sleep 15s again
not main thread will go on
I want to sleep 20s here


你可能感兴趣的:(C#,多线程)