线程同步之管程

管程:

线程同步的另一种方法就是使用管程类,它使用独占锁的方式控制线程的同步,只有只有获得独占锁的线程才能访问临界资源。
当一个线程进入临界区时,首先调用Monitor类的Enter()方法,尝试尝试获取临街资源的独占锁,若独占锁已被其他线程占用,就进入等待状态,直到释放独占锁为止。如果独占锁没有被其他线程占用,该线程会获取到独占锁,进入临界区,执行操作临界资源的代码。如果这时恰好有其他线程也来访问临界资源,后来的线程只能进行等待,睡眠在临界资源上。

Monitor会记录所有睡眠在临界资源上的线程,当线程退出临界区时,需要通过调用Monitor类地Pulse()方法唤醒睡眠在临界资源的线程。

Monitor类的部分方法如下:

        Monitor.Enter(object obj);//获取临界资源的独占锁,若不成功,则睡眠在临界资源上
        Monitor.TryEnter(object obj);//试图获取临街资源的独占锁,若不成功,立即返回
        Monitor.Pulse(object obj);//唤醒睡眠在临界资源上的线程
        Monitor.PulseAll(object obj);//唤醒睡眠在临界资源上的所有线程
        Monitor.Wait(object obj);//释放独占锁并让当前线程睡眠在临界资源上。
        Monitor.Exit(object obj);//释放独占锁,退出临界区

具体实现代码如下:

    private static char buffer;//缓存
    private static object lockForBuffer = new object();//操作对象
    void Start() {
        string sentence ="江上一笼统,井上黑窟窿。黄狗身上白,白狗身上肿";
        Thread Writer = new Thread(delegate ()
        {
            for (int i = 0; i < sentence.Length; i++)
            {
                try
                {
                    Monitor.Enter(lockForBuffer);//进入临界区
                    buffer = sentence[i];//向缓冲区写入数据
                    Monitor.Pulse(lockForBuffer);//唤醒睡眠在临界资源上的线程
                    Monitor.Wait(lockForBuffer);//让当前的线程睡眠在临街资源上

                }
                catch (System.Threading.ThreadInterruptedException)
                {

                    Debug.Log("线程Writer被终止");
                }
                finally
                {
                    Monitor.Exit(lockForBuffer);//退出临界区
                }
            }

        });
        Thread Reader = new Thread(delegate ()
        {
            for (int i = 0; i < sentence.Length; i++)
            {
                try
                {
                    Monitor.Enter(lockForBuffer);//进入临界区
                    char ch = buffer;
                    Debug.Log(ch);
                    Monitor.Pulse(lockForBuffer);//唤醒睡眠在临界资源上的线程
                    Monitor.Wait(lockForBuffer);//让当前的线程睡眠在临街资源上

                }
                catch (System.Threading.ThreadInterruptedException)
                {

                    Debug.Log("线程Reader被终止");
                }
                finally
                {
                    Monitor.Exit(lockForBuffer);//退出临界区
                }
            }
        });
        Writer.Start();
        Reader.Start();

注意:Monitor类只能锁定引用类对象,而不能锁定值类型对象。因为当参数为值类型变量时,每调用一次Monitor.Enter()方法,值类型变量就会进行一次装箱操作,每进行一次装箱操作,就得到一个新的Object型对象,因此,Monitor类的不同操作发生在不同的对象上,从而不能进行同步。

另外我们还可以使用更为简洁的Lock语句,lock语句执行完毕后就会自动执行Monitor.Exit()方法,释放临界资源。

具体代代码如下:

private static char buffer;
    private static object lockForBuffer = new object();
    void Start() {
        string sentence ="江上一笼统,井上黑窟窿。黄狗身上白,白狗身上肿";
        Thread Writer = new Thread(delegate ()
        {
            for (int i = 0; i < sentence.Length; i++)
            {
                locak(lockForBuffer)
                {
                    buffer = sentence[i];//向缓冲区写入数据
                    Monitor.Pulse(lockForBuffer);//唤醒睡眠在临界资源上的线程
                    Monitor.Wait(lockForBuffer);//让当前的线程睡眠在临街资源上
                }
                catch (System.Threading.ThreadInterruptedException)
                {

                    Debug.Log("线程Writer被终止");
                }
                finally
                {
                    Monitor.Exit(lockForBuffer);//退出临界区
                }
            }

        });
        Thread Reader = new Thread(delegate ()
        {
            for (int i = 0; i < sentence.Length; i++)
            {
                locak(lockForBuffer)
                {
                    char ch = buffer;
                    Debug.Log(ch);
                    Monitor.Pulse(lockForBuffer);//唤醒睡眠在临界资源上的线程
                    Monitor.Wait(lockForBuffer);//让当前的线程睡眠在临街资源上
                }
                catch (System.Threading.ThreadInterruptedException)
                {

                    Debug.Log("线程Reader被终止");
                }
                finally
                {
                    Monitor.Exit(lockForBuffer);//退出临界区
                }
            }
        });
        Writer.Start();
        Reader.Start();

说明:当一个线程以独占锁的方式访问资源时,其他线程就不能访问该资源,只有lock语句结束后其他线程才能访问,这保证了资源访问你的正确性。在某种意义上,lock语句的相当于临时禁用了应用程序的多线程功能。一般情况下,当有多个线程对同一个资源进行写操作时,就应该进行同步操作。

猜你喜欢

转载自blog.csdn.net/U3DJueQi/article/details/81389083