如何设计一个多读少写的多线程同步

1、如题:资源可能是很少次的写入,但是,会经常读写。如果使用lock,读一次,锁定一次资源;写一次,锁定一次资源。读取资源相对写入资源消耗会小一些,但是多次去读的话,每次锁定一次,会造成资源的浪费。

.Net FrameWork为我们提供了更好的解决方式,ReaderWriterLockSlim,这个类提供了一个锁定功能,如果没有写入器锁定资源,就允许多个读取器访问资源,但只能有一个写入器锁定该资源。

1》获取读取锁和写入锁的方式:

读取锁、写入锁获取方式
 读取锁写入锁
阻塞EnterReadLock()EnterWriterLock()
不阻塞TryEnterReadLock()TryEnterWriterLock()

 

 

 

 

什么情况下,获取写入锁定状态,而不用释放读取锁定?

如果是先读取资源,之后写入资源,就可以使用 EnterUpgradeableReadLock或者TryEnterUpgradeableReadLock方法获得可升级的锁定。

有了这个锁定,就可以获得写入锁定,而无需释放读取锁定。

2》属性

属性说明
CurrentReadCount获取以夺取模式进入锁定唯一线程总数
WaitingReadCount获取等待进入读取模式锁定状态的线程总数
WaitingUpgradeCount获取等待进入可升级模式锁定状态的总数
WaitingWriteCount获取等待进入写入模式锁定状态的线程总数

 

 

 

 

 

 

 场景:出板报和看板报,学校里我们出板报时,是由出板报的人员独自锁定了板报,进行作业。而到了看板报的时候,又可以有很多人同时看。我感觉这个例子挺适合。代码如下:

 class Program
 {
        static void Main(string[] args)
        {
            ReaderWriterDemo();
            Console.WriteLine("game over");
            Console.ReadLine();
        }
        #region 
        static void ReaderWriterDemo()
        {
            ReaderWriterLockSlim reader = new ReaderWriterLockSlim();
            //场景,出板报,就是一个例子,画板报的时候,需要一个写入器锁定资源,但是读取的时候就可以多个线程同时读取,
            //假如读取板报的人比较多,就得先看完,走了之后,剩下的才能看,也就相当源一个读取锁定了。

            var taskFactory = new TaskFactory(TaskCreationOptions.LongRunning, TaskContinuationOptions.None);
            var tasks = new Task[6];
            var w1 = new ReaderWriteLockDemo("w1");
            var w2 = new ReaderWriteLockDemo("w2");

            var r1 = new ReaderWriteLockDemo("r1");
            var r2 = new ReaderWriteLockDemo("r2");
            var r3 = new ReaderWriteLockDemo("r3");
            var r4 = new ReaderWriteLockDemo("r4");
            tasks[0] = taskFactory.StartNew(w1.Writer);
            tasks[1] = taskFactory.StartNew(r1.Reader);
            tasks[2] = taskFactory.StartNew(r2.Reader);
            tasks[3] = taskFactory.StartNew(w2.Writer);
            tasks[4] = taskFactory.StartNew(r3.Reader);
            tasks[5] = taskFactory.StartNew(r4.Reader);

            Task.WaitAll(tasks);
        }

        #endregion
         
    }

   public class ReaderWriteLockDemo
    {
        public static List<int> list = new List<int> { 5, 2, 6, 3, 5, 7, 7, 8, 10 };

        //声明一个读写对象。
        static ReaderWriterLockSlim _rwl = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);

        private string _name;
        public ReaderWriteLockDemo(string name)
        {
            this._name = name;
        }
        /// <summary>
        /// 看板报
        /// </summary>
        public void Reader()
        {
            try
            {
                _rwl.EnterReadLock();
                for(int i=0;i<list.Count;i++)
                {
                    WriteLine($" {this._name} 正在看 {list[i]} 内容 ");
                    Task.Delay(40).Wait();
                }
            }
            finally
            {
                _rwl.ExitReadLock();
            }
        }
        /// <summary>
        /// 画板报
        /// </summary>
        public void Writer()
        {
            try
            {
                while(!_rwl.TryEnterWriteLock(50))
                {
                    WriteLine($" 出板报人员{this._name} 等待写版本锁定");
                    WriteLine($" 当前的读者还有:{_rwl.WaitingReadCount}");
                }
                WriteLine($"{this._name} 写板报人员获得了锁定 ");
                for(int i=0;i<list.Count;i++)
                {
                    list[i]++;
                    Task.Delay(50).Wait();
                }
                WriteLine($"{this._name} 写完了");
            }
            finally
            {
                _rwl.ExitWriteLock();
            }
        }
    }

每天的点点滴滴,可能不尽如人意,请不吝赐教。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

fervour

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值