使用Monitor对资源进行保护(一)



首先,来看下使用system.threading.monitor对资源进行保护的思路:

 

即,使用排它锁,当线程A需要访问某一资源时,对其进行加锁,线程A获取到锁以后,任何其他线程如果再次对资源进行访问,则将其放到等待队列中,知道线程A释放锁之后,再将线程从队列中取出。

 

 主要的两个方法:


Enter

Exit

获取锁

释放锁

 

 

 接着是如何利用enter和exit方法实现线程保护的:



使用对象本身作为锁对象



using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Threading;



//使用monitor解决和上面类似的问题,
        //创建一个自定义的类型resource,然后在主线程和worker线程上调用他的record方法

namespace Monitor
{

    public class Resource {

        public string called;


        //定义要访问的资源
        public void Record() {


            this.called += string.Format("{0}{1}",Thread .CurrentThread .Name ,DateTime .Now .Millisecond);
            Console.WriteLine(called);
        }
    }

    class Program
    {
        private Resource res = new Resource();


        static void Main(string[] args)
        {
            Thread.CurrentThread.Name = "main ";

            Program p = new Program();
            Thread worker = new Thread(p.ThreadEntry );  //工作线程
            worker.Name = "worker";
            worker.Start();  //开启工作线程
            p.ThreadEntry();  //主线程中调用同样的方法

        }


        //要同时共享的方法
        void ThreadEntry() {

            
             System.Threading .Monitor.Enter(res);  //获取锁
                res.Record();
             System.Threading .Monitor.Exit(res);    //释放锁
            
        }
    }
}



使用System.Object作为锁对象



Monitor有一个限制,就是只能对引用类型加锁。
    如果将上面的Resource类型改为结构型,就会抛出异常

   解决的方法是将锁加载其他的引用类型上:
            比如system.object。此时,线程不会访问该引用类型的任何属性和方法,该对象的作用仅仅是协调各个线程。加锁思路:之前对于对象的加锁是占有A,操作A,释放A;现在的操作是占有B,操作A,释放B;




namespace 使用system.object作为锁对象
{


    //资源
    public struct Resource {

        public string Called;
        public void Record() {

            this.Called += string.Format("{0} {1}",Thread .CurrentThread .Name ,DateTime .Now .Millisecond);
            Console.WriteLine(Called);


        
        }
    }

    //
    class Program
    {
        private Resource res = new Resource();//资源
        private object lockobj = new object();  //用来加锁的介质

        private object lockobj2 = new object();

        static void Main(string[] args)
        {
            #region 只有一个加锁对象
                //Thread.CurrentThread.Name = "main ";

                //Program p = new Program();
                //Thread worker = new Thread(p.ThreadEntry);  //创建新线程
                //worker.Name = "worker";
                //worker.Start();  //开启新线程
                //p.ThreadEntry(); 
            #endregion



            #region 双对象:不能保证所有线程加锁和释放锁都是针对同一个对象B

            Thread.CurrentThread.Name = "main ";

            Program p = new Program();
            ParameterizedThreadStart ts = new ParameterizedThreadStart(p.ThreadEntry);


            Thread worker = new Thread(p.ThreadEntry);  //创建新线程
            worker.Name = "worker";

            //注意下面工作线程和主线程不是针对一个对象进行加锁的。。。运行时会得出他俩一起进入的时间
            worker.Start(p.lockobj);  //开启新线程
            p.ThreadEntry(p.lockobj2); 


            #endregion
        }


        void ThreadEntry(object obj) {


            Monitor.Enter(obj);
            res.Record();
            Monitor.Exit(obj);
        }

        #region 一个对象加锁
            //void ThreadEntry()
            //{

            //    Monitor.Enter(lockobj);//获取锁
            //    res.Record();
            //    Monitor.Exit(lockobj);//释放锁

            //} 
        #endregion
    }
}


使用System.Type作为锁对象


    为了改进使用System.Object作为锁对象时,需要单独创建一个对象加锁使用,不够简洁,所以使用Sytem.type作为锁对象。

   使用type的好处是:多次调用typeof(type)获取的是同一个对象


namespace 使用system.type作为锁对象
{
    class Program
    {
        static void Main(string[] args)
        {
            Thread.CurrentThread.Name = "main ";

            Program p = new Program();
            Thread worker = new Thread(p.ThreadEntry);  //创建新工作线程
            worker.Name = "worker";
            worker.Start();  //开启工作线程
            p.ThreadEntry(); //main里面开启工作线程

        }

        void ThreadEntry() {

            Monitor.Enter(typeof(Resource));//获取锁
            Resource.Record();
            Monitor.Exit(typeof (Resource));  //释放锁
        
        }
    }

    public static class Resource{
    
    
        public static string Called;


        public static void Record(){
        
            Called += String.Format("{0} {1}",Thread .CurrentThread .Name ,DateTime .Now .Millisecond);
            Console.WriteLine(Called);
        
        
        }
    
    }
}










评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值