勇哥注:
《多线程安全》这个系列会持续写下去,它是我的一个弱点,有兴趣的朋友可以选择性看看。
在C#中,赋值和简单的数字运算都不是原子型操作。在多线程环境下,会产生数据安全的问题。
Interlocked是“为多个线程共享的变量提供原子操作”,当然这个类是一个静态类。这个类的源代码看不到,因为是调用的CLR内部的方法,不过基本思想应该是通过硬件原语try and set来实现的。
该类提供的Add、Increment、Decrement能够完成简单的原子操作。
方法 | 作用 |
CompareExchange() | 安全比较两个值是不是相等。如果相等,将第三个值于其中一个值交换 |
Decrement() | 安全递减1,相当于 i-- |
Exchange() | 安全交换数据,相当于 a = 30 |
Increment() | 安全递加1,相当于 i++ |
Add() | 安全相加一个数值,相当于 a = a + 3 |
Read() | 安全读取数值,相等于int a=b |
先来演示一下安全递减与递加。
看剑法:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; namespace WindowsFormsApplication1 { public partial class Form1 : Form { static int counter = 1; public Form1() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { Thread t1 = new Thread(new ThreadStart(F1)); Thread t2 = new Thread(new ThreadStart(F2)); t1.Start(); t2.Start(); t1.Join(); t2.Join(); } static void F1() { for (int i = 0; i < 5; i++) { Interlocked.Increment(ref counter); System.Console.WriteLine("Counter++ {0}", counter); Thread.Sleep(10); } } static void F2() { for (int i = 0; i < 5; i++) { Interlocked.Decrement(ref counter); System.Console.WriteLine("Counter-- {0}", counter); Thread.Sleep(10); } } } }
每次运行结果都不会一样。
下面是较完美的一种,f1和f2在交替运行。
不完美的时候,有时候f1和f2分别多运行几次。
再来一个例子:
还是加与减。
private void button2_Click(object sender, EventArgs e) { TestIncrementUnSafe(); TestIncrementSafe(); } private int value1 = 0; public void TestIncrementUnSafe() { for (int i = 0; i < 5; i++) { Thread t = new Thread(IncrementValue1); t.Name = "t1 " + i; t.Start(); } Thread.Sleep(2000); Console.WriteLine("value1 = " + value1); } private int value2 = 0; public void TestIncrementSafe() { for (int i = 0; i < 5; i++) { Thread t = new Thread(IncrementValue2); t.Name = "t2 " + i; t.Start(); } Thread.Sleep(2000); Console.WriteLine("value2 = " + value2); } private void IncrementValue1() { for (int i = 0; i < 1000000; i++) { value1++; } } private void IncrementValue2() { for (int i = 0; i < 1000000; i++) { Interlocked.Increment(ref value2); } }
这里可以看到对比效果,有安全的和没有安全的加减结果是不同的。
来试试
Exchange和CompareExchange
即安全的赋值与比较
private int value3 = 0; public void TestExchangeSafe() { for (int i = 0; i < 5; i++) { Thread t = new Thread(ExchangeValue3); t.Name = "t2 " + i; value3 = i; t.Start(); } Thread.Sleep(2000); //value should be 83 Console.WriteLine("value3 = " + value3); } private void ExchangeValue3() { Interlocked.Exchange(ref value3, 83); } private int value4 = 0; public void TestCompareExchangeSafe() { for (int i = 0; i < 5; i++) { Thread t = new Thread(ExchangeValue4); t.Name = "t2 " + i; t.Start(); } Thread.Sleep(2000); //value should be 99 or 0 Console.WriteLine("value4 = " + value4); } private void ExchangeValue4() { //if value4=0, set value4=99 Interlocked.CompareExchange(ref value4, 99, 0); } private void button3_Click(object sender, EventArgs e) { TestExchangeSafe(); TestCompareExchangeSafe(); }
---------------------
作者:hackpig
来源:www.skcircle.com
版权声明:本文为博主原创文章,转载请附上博文链接!

