联合与异步之锁(Lock、Monitor)(七),.NET 同步与异步之锁(Lock、Monitor)

本小说续接:.NET
同步与异步之锁(Lock、Monitor)(七)

本小说续接:.NET 同步与异步之锁(Lock、Monitor)

 

是因为锁 ( lock 和 Monitor )
是线程独占式访问的,所以其对质量的熏陶照旧蛮大的,这有没有一种艺术可是落实:允许多少个线程同时读数据、只同意一个线程写多少吧?答案是一定的。

由于锁 ( lock 和 Monitor )
是线程独占式访问的,所以其对品质的熏陶只怕蛮大的,这有没有一种格局不过落到实处:允许多个线程同时读数据、只允许多少个线程写多少吧?答案是一定的。

读写锁ReaderWriterLock、正是 补助单个写线程和多少个读线程的锁。自.NET 3.5
开头ReaderWriterLockSlim、登上舞台,ReaderWriterLockSlim可以看作是ReaderWriterLock的升级版。
由于 ReaderWriterLockSlim
暗中同意不援救递归调用、所以在某种意义上来说更不不难导致死锁。

 

一 、先看一下demo(来源msdn代码示例):

读写锁 ReaderWriterLock 、正是扶助单个写线程和五个读线程的锁。自.NET 3.5
发轫 ReaderWriterLockSlim 、登上舞台,ReaderWriterLockSlim 能够当作是 ReaderWriterLock 的升级版。
由于 ReaderWriterLockSlim 
暗中同意不协助递归调用、所以在某种意义上来说更不便于造成死锁。

图片 1图片 2

 

    public class SynchronizedCache    {        private ReaderWriterLockSlim cacheLock = new ReaderWriterLockSlim();        private Dictionary<int, string> innerCache = new Dictionary<int, string>();        public int Count        { get { return innerCache.Count; } }        public string Read(int key)        {            cacheLock.EnterReadLock();            try            {                return innerCache[key];            }            finally            {                cacheLock.ExitReadLock();            }        }        public void Add(int key, string value)        {            cacheLock.EnterWriteLock();            try            {                innerCache.Add(key, value);            }            finally            {                cacheLock.ExitWriteLock();            }        }        public bool AddWithTimeout(int key, string value, int timeout)        {            if (cacheLock.TryEnterWriteLock            {                try                {                    innerCache.Add(key, value);                }                finally                {                    cacheLock.ExitWriteLock();                }                return true;            }            else            {                return false;            }        }        public AddOrUpdateStatus AddOrUpdate(int key, string value)        {            cacheLock.EnterUpgradeableReadLock();            try            {                string result = null;                if (innerCache.TryGetValue(key, out result))                {                    if (result == value)                    {                        return AddOrUpdateStatus.Unchanged;                    }                    else                    {                        cacheLock.EnterWriteLock();                        try                        {                            innerCache[key] = value;                        }                        finally                        {                            cacheLock.ExitWriteLock();                        }                        return AddOrUpdateStatus.Updated;                    }                }                else                {                    cacheLock.EnterWriteLock();                    try                    {                        innerCache.Add(key, value);                    }                    finally                    {                        cacheLock.ExitWriteLock();                    }                    return AddOrUpdateStatus.Added;                }            }            finally            {                cacheLock.ExitUpgradeableReadLock();            }        }        public void Delete(int key)        {            cacheLock.EnterWriteLock();            try            {                innerCache.Remove;            }            finally            {                cacheLock.ExitWriteLock();            }        }        public enum AddOrUpdateStatus        {            Added,            Updated,            Unchanged        };        ~SynchronizedCache()        {            if (cacheLock != null) cacheLock.Dispose();        }    }        private void ReaderWriterLock()        {            var sc = new SynchronizedCache();            var tasks = new List<Task>();            int itemsWritten = 0;            // Execute a writer.            tasks.Add(Task.Run =>            {                String[] vegetables = { "broccoli", "cauliflower",                                                          "carrot", "sorrel", "baby turnip",                                                          "beet", "brussel sprout",                                                          "cabbage", "plantain",                                                          "spinach", "grape leaves",                                                          "lime leaves", "corn",                                                          "radish", "cucumber",                                                          "raddichio", "lima beans" };                for (int ctr = 1; ctr <= vegetables.Length; ctr++)                    sc.Add(ctr, vegetables[ctr - 1]);                itemsWritten = vegetables.Length;                base.PrintInfo(string.Format("Task {0} wrote {1} items\n", Task.CurrentId, itemsWritten));            }));            // Execute two readers, one to read from first to last and the second from last to first.            for (int ctr = 0; ctr <= 1; ctr++)            {                bool desc = Convert.ToBoolean;                tasks.Add(Task.Run =>                {                    int start, last, step;                    int items;                    do                    {                        String output = String.Empty;                        items = sc.Count;                        if (!desc)                        {                            start = 1;                            step = 1;                            last = items;                        }                        else                        {                            start = items;                            step = -1;                            last = 1;                        }                        for (int index = start; desc ? index >= last : index <= last; index += step)                            output += String.Format("[{0}] ", sc.Read;                        base.PrintInfo(string.Format("Task {0} read {1} items: {2}\n", Task.CurrentId, items, output));                    } while (items < itemsWritten | itemsWritten == 0);                }));            }            // Execute a red/update task.            tasks.Add(Task.Run =>            {                Thread.Sleep(100);                for (int ctr = 1; ctr <= sc.Count; ctr++)                {                    String value = sc.Read;                    if (value == "cucumber")                        if (sc.AddOrUpdate(ctr, "green bean") != SynchronizedCache.AddOrUpdateStatus.Unchanged)                            base.PrintInfo("Changed 'cucumber' to 'green bean'");                }            }));            // Wait for all three tasks to complete.            Task.WaitAll(tasks.ToArray;            // Display the final contents of the cache.            base.PrintInfo("");            base.PrintInfo("Values in synchronized cache: ");            for (int ctr = 1; ctr <= sc.Count; ctr++)                base.PrintInfo(string.Format("   {0}: {1}", ctr, sc.Read;        }

① 、先看一下demo(来源msdn代码示例):

Demo

图片 3图片 4

② 、通过Demo大家来看一下ReaderWriterLockSlim的用法:

    public class SynchronizedCache
    {
        private ReaderWriterLockSlim cacheLock = new ReaderWriterLockSlim();
        private Dictionary<int, string> innerCache = new Dictionary<int, string>();

        public int Count
        { get { return innerCache.Count; } }

        public string Read(int key)
        {
            cacheLock.EnterReadLock();
            try
            {
                return innerCache[key];
            }
            finally
            {
                cacheLock.ExitReadLock();
            }
        }

        public void Add(int key, string value)
        {
            cacheLock.EnterWriteLock();
            try
            {
                innerCache.Add(key, value);
            }
            finally
            {
                cacheLock.ExitWriteLock();
            }
        }

        public bool AddWithTimeout(int key, string value, int timeout)
        {
            if (cacheLock.TryEnterWriteLock(timeout))
            {
                try
                {
                    innerCache.Add(key, value);
                }
                finally
                {
                    cacheLock.ExitWriteLock();
                }
                return true;
            }
            else
            {
                return false;
            }
        }

        public AddOrUpdateStatus AddOrUpdate(int key, string value)
        {
            cacheLock.EnterUpgradeableReadLock();
            try
            {
                string result = null;
                if (innerCache.TryGetValue(key, out result))
                {
                    if (result == value)
                    {
                        return AddOrUpdateStatus.Unchanged;
                    }
                    else
                    {
                        cacheLock.EnterWriteLock();
                        try
                        {
                            innerCache[key] = value;
                        }
                        finally
                        {
                            cacheLock.ExitWriteLock();
                        }
                        return AddOrUpdateStatus.Updated;
                    }
                }
                else
                {
                    cacheLock.EnterWriteLock();
                    try
                    {
                        innerCache.Add(key, value);
                    }
                    finally
                    {
                        cacheLock.ExitWriteLock();
                    }
                    return AddOrUpdateStatus.Added;
                }
            }
            finally
            {
                cacheLock.ExitUpgradeableReadLock();
            }
        }

        public void Delete(int key)
        {
            cacheLock.EnterWriteLock();
            try
            {
                innerCache.Remove(key);
            }
            finally
            {
                cacheLock.ExitWriteLock();
            }
        }

        public enum AddOrUpdateStatus
        {
            Added,
            Updated,
            Unchanged
        };

        ~SynchronizedCache()
        {
            if (cacheLock != null) cacheLock.Dispose();
        }
    }


        private void ReaderWriterLock()
        {
            var sc = new SynchronizedCache();
            var tasks = new List<Task>();
            int itemsWritten = 0;

            // Execute a writer.
            tasks.Add(Task.Run(() =>
            {
                String[] vegetables = { "broccoli", "cauliflower",
                                                          "carrot", "sorrel", "baby turnip",
                                                          "beet", "brussel sprout",
                                                          "cabbage", "plantain",
                                                          "spinach", "grape leaves",
                                                          "lime leaves", "corn",
                                                          "radish", "cucumber",
                                                          "raddichio", "lima beans" };
                for (int ctr = 1; ctr <= vegetables.Length; ctr++)
                    sc.Add(ctr, vegetables[ctr - 1]);

                itemsWritten = vegetables.Length;

                base.PrintInfo(string.Format("Task {0} wrote {1} items\n", Task.CurrentId, itemsWritten));
            }));
            // Execute two readers, one to read from first to last and the second from last to first.
            for (int ctr = 0; ctr <= 1; ctr++)
            {
                bool desc = Convert.ToBoolean(ctr);
                tasks.Add(Task.Run(() =>
                {
                    int start, last, step;
                    int items;
                    do
                    {
                        String output = String.Empty;
                        items = sc.Count;
                        if (!desc)
                        {
                            start = 1;
                            step = 1;
                            last = items;
                        }
                        else
                        {
                            start = items;
                            step = -1;
                            last = 1;
                        }

                        for (int index = start; desc ? index >= last : index <= last; index += step)
                            output += String.Format("[{0}] ", sc.Read(index));

                        base.PrintInfo(string.Format("Task {0} read {1} items: {2}\n", Task.CurrentId, items, output));

                    } while (items < itemsWritten | itemsWritten == 0);
                }));
            }
            // Execute a red/update task.
            tasks.Add(Task.Run(() =>
            {
                Thread.Sleep(100);
                for (int ctr = 1; ctr <= sc.Count; ctr++)
                {
                    String value = sc.Read(ctr);
                    if (value == "cucumber")
                        if (sc.AddOrUpdate(ctr, "green bean") != SynchronizedCache.AddOrUpdateStatus.Unchanged)
                            base.PrintInfo("Changed 'cucumber' to 'green bean'");
                }
            }));

            // Wait for all three tasks to complete.
            Task.WaitAll(tasks.ToArray());

            // Display the final contents of the cache.
            base.PrintInfo("");
            base.PrintInfo("Values in synchronized cache: ");
            for (int ctr = 1; ctr <= sc.Count; ctr++)
                base.PrintInfo(string.Format("   {0}: {1}", ctr, sc.Read(ctr)));
        }

① 、EnterWriteLock 进入写格局锁定状态

Demo

二 、EnterReadLock 进入读格局锁定状态

 

三 、EnterUpgradeableReadLock进入可进步的读方式锁定状态

二 、通过Demo大家来看一下 ReaderWriterLockSlim  的用法:

再者两种锁定格局都有逾期机制、对应 Try… 方法,退出相应的模式则使用
Exit… 方法,而且具有的不二法门都不能够不是成对出现的。

1、EnterWriteLock  进入写形式锁定状态

③ 、备注及注意事项

2、EnterReadLock  
 进入读形式锁定状态

壹 、对于同一把锁、三个线程可同时进入 读情势。

3、EnterUpgradeableReadLock  进入可进步的读格局锁定状态

贰 、对于同一把锁、同时只同意一个线程进入 写情势。

同时三种锁定方式都有逾期机制、对应 Try… 方法,退出相应的方式则选取Exit… 方法,而且具备的措施都无法不是成对出现的。

叁 、对于同一把锁、同时只允许二个线程进入 可升级的读格局。

 

④ 、通过暗中同意构造函数创造的读写锁是不扶助递归的,若想匡助递归
可透过结构ReaderWriterLockSlim(LockRecursionPolicy)制造实例。

③ 、备注及注意事项

5、对于同一把锁、同一线程不可四遍跻身同一锁状态

① 、对于同一把锁、多少个线程可同时进入 读格局。

六 、对于同一把锁、就算开启了递归、也无法在进入读方式后再一次进入写格局可能可升高的读格局(在那前边务必剥离读格局)。

② 、对于同一把锁、同时只允许2个线程进入 写格局。

柒 、再次强调、不提出启用递归。

③ 、对于同一把锁、同时只允许1个线程进入 可提升的读情势。

八 、读写锁具备线程关联性,即 五个线程间拥有的锁的情事
相互独立不受影响、并且不能够互相修改其锁的事态。

 

⑨ 、升级状态:在进入可进步的读形式EnterUpgradeableReadLock后,可在适度时间点
通过EnterWriteLock 进入写方式。

④ 、通过暗中认可构造函数创制的读写锁是不帮忙递归的,若想帮忙递归
可透过结构 ReaderWriterLockSlim(LockRecursionPolicy) 创造实例。

⑩ 、降级状态:可升级的读形式能够降级为读情势:即在进入可提高的读方式EnterUpgradeableReadLock后,通过首先调用读取方式EnterReadLock方法,然后再调用ExitUpgradeableReadLock方法。

伍 、对于同一把锁、同一线程不可三遍跻身同一锁状态(开启递归后能够)

小说暂告一段落、下一篇小说介绍:轻量级的锁(Interlocked、SpinLock)

陆 、对于同一把锁、尽管开启了递归、也不能够在进入读情势后重新进入写情势可能可升级的读情势(在那在此之前必须退出读格局)。

附,Demo :http://files.cnblogs.com/files/08shiyan/ParallelDemo.zip

七 、再度强调、不提出启用递归。

参见更加多:小说导读:同步与异步

八 、读写锁具备线程关联性,即 五个线程间拥有的锁的事态
相互独立不受影响、并且无法互相修改其锁的情状。

 

玖 、升级状态:在进入可提高的读情势 EnterUpgradeableReadLock  后,可在适当时间点
通过 EnterWriteLock  
进入写方式。

⑩ 、降级状态:可升级的读格局能够降级为读形式:即 在进入可升级的读方式 EnterUpgradeableReadLock  后, 通过首先调用读取情势 EnterReadLock 方法,然后再调用 ExitUpgradeableReadLock 方法。 

 

 

小说暂告一段落、下一篇随笔介绍:轻量级的锁(Interlocked、SpinLock)(估计1篇随笔)

附,Demo : http://files.cnblogs.com/files/08shiyan/ParallelDemo.zip

参见更加多:随笔导读:同步与异步

(未完待续…)

相关文章