.NET线程同步之Interlocked构造
来源:互联网 发布:js中校验身份证合法性 编辑:程序博客网 时间:2024/06/06 01:12
接着上一篇博客.NET线程同步之Volatile构造,本篇来讨论如何使用Interlocked来处理线程安全的原子性读写操作。
引出问题
开始详细介绍System.Threading.Interlocked
类之前,我们来先实现一个功能:在多个线程中同时增长一个公共变量。
static void Main(string[] args){ Parallel.For(0, 10000, i => ChangeValue(1)); Console.WriteLine(value);}static int value = 0;static void ChangeValue(int addValue){ value += addValue;}
上面的代码创建了10000个任务,每个任务都让公有变量value
加一,线程池会分配线程来运行这10000个任务,由于避免不了并发,所以,总会有一些写入操作同时执行而造成value
的更新被覆盖,所以,上面代码的运行结果经常是小于10000的。具体原因如下:
在某个时间点,假设当前公共变量value
的值是1000,有两个线程同时将value
加一并写入,value
最终的结果就会变成1001,而不是我们希望的1002。
使用Interlocked
类来解决问题
下面使用Interlocked.Add()
方法来实现。
static void Main(string[] args){ Parallel.For(0, 10000, i => ChangeValueWithInterlock(1)); Console.WriteLine(value);}static int value = 0;static void ChangeValueWithInterlock(int addValue){ Interlocked.Add(ref value, addValue);}
运行上面的代码,每次返回的结果都是10000。
Interlocked类的每一个方法都执行一个原子级的读取并写入操作。并且,它的每一个方法都是建立了完整的内存栅栏(memory fence),可以保证在Interlocked的方法在执行期间,不允许其它方法对指定的共有变量进行写入和读取。
Interlocked
类的常用方法
下面列举几个Interlocked
类的常用方法。这个类不仅支持int类型,还支持float、double、long类型以及对象类型(有一个泛型重载)。在此我仅列举int类型的版本。
public static int Add(ref int location, int value)
上面这个是刚才我们使用的方法,对location
所在的变量进行原子级的add。
public static int Increment(ref int location)
上面这个方法相当于Interlocked.Add(ref location, 1)
;
public static int Decrement(ref int location)
上面这个方法相当于Interlocked.Add(ref location, -1)
;
public static int Exchange(ref int location, int value)
上面这个方法稍微复杂一点,但是很常用,它将location
所对应的变量的值替换为value
,并返回location
被替换之前的值。假设多个线程同时竞争一个公共资源,可以定义一个值为0的公共变量,然后调用Interlocked.Exchange()
方法去将它更新为1,哪个线程的方法的返回值是0,则这个线程在竞争中胜出。因为只有一个线程能够将这个共有变量由0更新为1。这也是SpinLock
的大致实现原理。我在接下来的博客中会专门介绍SpinLock
的用法。
public static int CompareExchange(ref int location, int value, int comparand)
上面这个方法更复杂一点,它先比较locating
所对应的变量的值是否等于comparand
,如果相等,则将location
对应的变量更新为value
。这个方法总是返回location
原来的值,所以,如果comparand
的值等于该方法的返回值,则说明location
对应的变量被成功地更新了。
这个方法的用法可以非常灵活,我介绍其中的一种吧,它可以用来做乐观并发,具体来说是这样子的:假设你要更新一个公共资源,你先读取它当前的值保存在一个临时变量中,然后可以去做点别的操作,最后调用Interlocked.CompareExchange()
方法去更新它的值,如果该方法返回的值跟临时变量中的值不一样,说明你读到了脏数据,更新失败!需要再次重复这个流程来更新。
- .NET线程同步之Interlocked构造
- .NET线程同步之Interlocked和ReadWrite锁
- Windows线程同步之互锁函数(Interlocked)
- .NET线程同步之Volatile构造
- .NET线程同步之SpinLock构造
- c#之线程同步浅析(1)-----轻量级同步Interlocked
- c#之线程同步浅析(1)-----轻量级同步Interlocked
- Windows线程同步之互锁函数(Interlocked)
- .Net下的线程同步:Part 5 of N--(Interlocked && Volatile...)
- 线程同步一:InterLocked系列函数
- Windows线程同步--互锁变量访问(Interlocked)
- Interlocked系列函数线程同步的缺陷
- 线程同步(使用Interlocked类)
- 线程同步 旋转锁 Interlocked 用户模式同步对象 InterlockedExchange
- 用户模式的线程同步原子访问:InterLocked互锁函数
- .NET多线程同步方法详解(一):自由锁(InterLocked)
- NET多线程同步方法详解(一):自由锁(InterLocked)
- NET多线程同步方法详解(一):自由锁(InterLocked)
- OpenStack mitaka,lbaasV2安装
- LintCode-最大正方形&最大矩形
- 如何定位问题
- oracle中exists和in的区别和效率比较
- Git和SVN的区别
- .NET线程同步之Interlocked构造
- 获取客户端IP地址
- jzoj. 3522. 【NOIP2013模拟11.7B组】迷宫花园(maze)
- 文章标题
- 从技术角度来说说区块链到底有哪些特点和运作机制
- Android中带有输入框的自定义Dialog
- remove-nth-node-from-end-of-list
- 如何设计一个牛掰的大型项目架构?
- 问题: Manifest merger failed : Attribute application@allowBackup value=(false) 解决方法