勇哥注:
《多线程安全》这个系列会持续写下去,它是我的一个弱点,有兴趣的朋友可以选择性看看。
在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
版权声明:本文为博主原创文章,转载请附上博文链接!

