C# 多线程安全(5)Interlocked共享变量原子操作锁

勇哥注:

《多线程安全》这个系列会持续写下去,它是我的一个弱点,有兴趣的朋友可以选择性看看。


在C#中,赋值和简单的数字运算都不是原子型操作。在多线程环境下,会产生数据安全的问题。

Interlocked是“为多个线程共享的变量提供原子操作”,当然这个类是一个静态类。这个类的源代码看不到,因为是调用的CLR内部的方法,不过基本思想应该是通过硬件原语try and set来实现的。

该类提供的Add、Increment、Decrement能够完成简单的原子操作。


Interlocked类主要方法

方法
作用
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分别多运行几次。

image.png


再来一个例子:

还是加与减。

   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);
            }
        }

这里可以看到对比效果,有安全的和没有安全的加减结果是不同的。

image.png



来试试

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();
        }


image.png


--------------------- 

作者:hackpig

来源:www.skcircle.com

版权声明:本文为博主原创文章,转载请附上博文链接!


本文出自勇哥的网站《少有人走的路》wwww.skcircle.com,转载请注明出处!讨论可扫码加群:

发表评论:

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。

会员中心
搜索
«    2024年4月    »
1234567
891011121314
15161718192021
22232425262728
2930
网站分类
标签列表
最新留言
    热门文章 | 热评文章 | 随机文章
文章归档
友情链接
  • 订阅本站的 RSS 2.0 新闻聚合
  • 扫描加本站机器视觉QQ群,验证答案为:halcon勇哥的机器视觉
  • 点击查阅微信群二维码
  • 扫描加勇哥的非标自动化群,验证答案:C#/C++/VB勇哥的非标自动化群
  • 扫描加站长微信:站长微信:abc496103864
  • 扫描加站长QQ:
  • 扫描赞赏本站:
  • 留言板:

Powered By Z-BlogPHP 1.7.2

Copyright Your skcircle.com Rights Reserved.

鄂ICP备18008319号


站长QQ:496103864 微信:abc496103864