• linkedu视频
  • 平面设计
  • 电脑入门
  • 操作系统
  • 办公应用
  • 电脑硬件
  • 动画设计
  • 3D设计
  • 网页设计
  • CAD设计
  • 影音处理
  • 数据库
  • 程序设计
  • 认证考试
  • 信息管理
  • 信息安全
菜单
linkedu.com
  • 网页制作
  • 数据库
  • 程序设计
  • 操作系统
  • CMS教程
  • 游戏攻略
  • 脚本语言
  • 平面设计
  • 软件教程
  • 网络安全
  • 电脑知识
  • 服务器
  • 视频教程
  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号
您的位置:首页 > 程序设计 >C#教程 > C#多线程编程中的锁系统(二)

C#多线程编程中的锁系统(二)

作者: 字体:[增加 减小] 来源:互联网 时间:2017-05-28

通过本文主要向大家介绍了c#多线程,c#多线程编程实例,c#多线程编程,c#多线程同步,c#多线程实例等相关知识,希望对您有所帮助,也希望大家支持linkedu.com www.linkedu.com

上章主要讲排他锁的直接使用方式。但实际当中全部都用锁又太浪费了,或者排他锁粒度太大了。 这一次我们说说升级锁和原子操作。

目录
1:volatile
2:  Interlocked
3:ReaderWriterLockSlim
4:总结

一:volatile

简单来说: volatile关键字是告诉c#编译器和JIT编译器,不对volatile标记的字段做任何的缓存。确保字段读写都是原子操作,最新值。

这不就是锁吗?   其这货它根本不是锁, 它的原子操作是基于CPU本身的,非阻塞的。 因为32位CPU执行赋值指令,数据传输最大宽度4个字节。

所以只要在4个字节以下读写操作的,32位CPU都是原子操作。volatile 它就是利用这个特性来的。

好残酷的事实?不然,微软大法这样是为了提高JIT性能效率,对有些数据进行缓存了(多线程下)。

  //正确
       public volatile Int32 score1 = 1;
        //报错
        public volatile Int64 score2 = 1;
</div>

看上面的例子,我们定义8个字节长度score2就不行了。  因为8个字节,32位CPU就分成2个指令执行了。自然就无法保证原子操作了。

这么细节的,忘了怎么办,那岂不是坑人啊。  于是微软大法直接一棍子打死,限制4个字节以下的类型字段才能用volatile,具体什么、看msdn吧。

那今天我知道了。我编译平台改成64位上,只在64位CPU用volatile  int64,行不行?  不行,编译器报错。说了一棍子打死了。。

(^._.^)ノ  好吧,其实可以用IntPtr这个。

 volatile多数情况下很有用处的,毕竟锁的性能开销还是很大的。我们可以把当成轻量级的锁,根据具体场景合理使用,能提高不少程序性能。

线程中的Thread.VolatileRead 和Thread.VolatileWrite 就是volatile的复杂版。

二:Interlocked

MSDN 描述:为多个线程共享的变量提供原子操作。主要函数如下:

Interlocked.Increment    原子操作,递增指定变量的值并存储结果。
Interlocked.Decrement       原子操作,递减指定变量的值并存储结果。
Interlocked.Add        原子操作,添加两个整数并用两者的和替换第一个整数

Interlocked.CompareExchange(ref a, b, c);  原子操作,a参数和c参数比较,  相等b替换a,不相等不替换。

基本用法就不多说了。直接来段CLR via C# interlock anything的例子:
public static int Maximum(ref int target, int value)
        {
            int currentVal = target, startVal, desiredVal;  //记录前后值
            do
            {
                startVal = currentVal; //记录循环迭代的初始值。
                desiredVal = Math.Max(startVal, value); //基于startVal和value计算期望值desiredVal

                //高并发下,线程被抢占情况下,target值会发生改变。

                //target startVal相等说明没改变。desiredVal 直接替换。
                currentVal = Interlocked.CompareExchange(ref target, desiredVal, startVal);

            } while (startVal != currentVal); //不相等说明,target值已经被其他线程改动。自旋继续。
            return desiredVal;
        }
</div>

三:ReaderWriterLockSlim

假如我们有份缓存数据A,如果每次都不管任何操作lock一下,那么我的这份缓存A就永远只能单线程读写了, 这在Web高并发下是不能忍受的。

那有没有一种办法我只在写入时进入独占锁呢,读操作时不限制线程数量呢?答案就是我们的ReaderWriterLockSlim主角,读写锁。

ReaderWriterLockSlim 其中一种锁EnterUpgradeableReadLock最关键  即可升级锁。 

它呢允许你先进入读锁,发现缓存A不一样了, 再进入写锁,写入后退回读锁模式。

ps: 这里注意下net 3.5之前有个ReaderWriterLock 性能较差。推荐使用升级版的 ReaderWriterLockSlim 。
//实例一个读写锁
 ReaderWriterLockSlim cacheLock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);
</div>
上面实例一个读写锁,这里注意的是构造函数的枚举。

LockRecursionPolicy.NoRecursion 不支持,发现递归会抛异常。

LockRecursionPolicy.SupportsRecursion  即支持递归模式,线程锁中继续在使用锁。

cacheLock.EnterReadLock();
            //do
                cacheLock.EnterReadLock();
                //do
                cacheLock.ExitReadLock();
            cacheLock.ExitReadLock();
</div>

这种模式极易容易死锁,比如读锁里面使用写锁。
cacheLock.EnterReadLock();
            //do
              cacheLock.EnterWriteLock();
              //do
              cacheLock.ExitWriteLock();
            cacheLock.ExitReadLock();
</div>

下面是直接拿msdn的缓存例子了,加了简单注释。
public class SynchronizedCache
    {
        private ReaderWriterLockSlim cacheLock = new ReaderWriterLockSlim();
        private Dictionary<int, string> innerCache = new Dictionary<int, string>();

        public string Read(int key)
        {
            //进入读锁,允许其他所有的读线程,写入线

分享到:QQ空间新浪微博腾讯微博微信百度贴吧QQ好友复制网址打印

您可能想查找下面的文章:

  • C#多线程编程详解
  • C#制作多线程处理强化版网络爬虫
  • C#向线程中传递多个参数的解决方法(两种)
  • C#往线程里传递参数的方法小结
  • C#中实现线程同步lock关键字的用法详解
  • C#下载歌词文件的同步和异步方法
  • C#多线程传递参数及任务用法示例
  • C#模式画刷HatchBrush用法实例
  • C#纹理画刷TextureBrush用法实例
  • c#实现多线程局域网聊天系统

相关文章

  • 2017-05-28C# WinForm编程获取文件物理路径的方法
  • 2017-05-28c#通过ip获取地理信息
  • 2017-05-28使用C#获取网页HTML源码的例子
  • 2017-05-28C#编程实现四舍五入、向上及下取整的方法
  • 2017-05-28C#最简单的字符串加密解密方法
  • 2017-05-28C#简单连接sql数据库的方法
  • 2017-05-28C#操作txt文件,进行清空添加操作的小例子
  • 2017-05-28C#使用round函数四舍五入的方法
  • 2017-05-28C#使用linq语句查询数组中以特定字符开头元素的方法
  • 2017-05-28openfiledialog读取txt写入数据库示例

文章分类

  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号

最近更新的内容

    • C#基础之匿名方法实例教程
    • C#动态生成PictureBox并指定图片的方法
    • Gridview自动排序功能的实现
    • c#保存窗口位置大小操作类(序列化和文件读写功能)
    • 那些年,我还在学习C# 学习笔记续
    • 浅谈C#设计模式之开放封闭原则
    • C#实现DataTable映射成Model的方法(附源码)
    • C#操作目录与文件的方法步骤
    • C#实现汉字转换为拼音缩写的代码
    • c#入门之类型转换详解

关于我们 - 联系我们 - 免责声明 - 网站地图

©2020-2025 All Rights Reserved. linkedu.com 版权所有