接昨天谈及的线程同步问题,今天介绍一个比较简单的类,Interlocked。它提供了以线程安全的方式递增、递减、交换和读取值的方法。

它的特点是:

1、相对于其他线程同步技术,速度会快很多。

2、只能用于简单的同步问题。

比叫好理解,不再赘述,给一个我们常用的单例模式的 Interlocked 实现:

        class SourceManager
{
private SourceManager() { } private static SourceManager sourceManager;
public static SourceManager Instance
{
get
{
if (sourceManager == null)
{
/* lock 实现方式
功能与以下 Interlocked.CompareExchange 相同 lock (this)
{
if (sourceManager == null)
{
sourceManager = new SourceManager();
}
} */
Interlocked.CompareExchange<SourceManager>(ref sourceManager, new SourceManager(), null);
}
return sourceManager;
}
}
}

Interlocked 类用于使变量的简单语句原子化。再用一个例子说明用 Interlocked 实现线程安全资源锁定机制。

在这个例子中,我们会建立10任务,每个任务会分别循环50000次请求使用资源,而这种资源我们限定同一时间只能有一个线程访问,请求成功则递增 accessed 值,失败则递增 denied 值,因此按我们的预期,accessed 和 denied 的和将会始终是 10*50000 = 500000。且看我们设计的机制:

    class InterlockedCase
{
private static int accessed = ;
private static int denied = ; // 0 没有线程在使用 1 有线程正在使用
private static int usingResource = ; private const int nTaskIterations = ;
private const int nTasks = ; public static void Test()
{
Task[] tasks = new Task[nTasks];
for (int i = ; i < nTasks; i++)
{
tasks[i] = Task.Factory.StartNew(ThreadProc);
}
for (int i = ; i < nTasks; i++)
{
tasks[i].Wait();
}
Console.WriteLine("accessed:{0}, denied:{1}, total:{2}", accessed, denied, accessed+denied);
} private static void ThreadProc()
{
for (int i = ; i < nTaskIterations; i++)
{
UseResource();
}
} private static bool UseResource()
{
if (usingResource == )
{
usingResource = ; accessed++; usingResource = ;
return true;
}
else
{
Interlocked.Increment(ref denied);
return false;
}
}
}

上面例子的运行结果total值却不是我们预期的总请求数 50000!

在代码中,我们设计了一个访问共享资源的逻辑

if (usingResource == 0)
{
  usingResource = 1;

  accessed++;

  usingResource = 0;
  return true;
}

错误的原因是我们控制资源的逻辑里 usingResource 的判断和赋值操作并不是原子操作,会导致有多个线程能同时进入内层操纵资源,修改 accessed!导致 accessed 值的统计不准确!

找到原因,我们把 usingResource 的判断和赋值转为原子操作,就能实现我们的构想了,Interlocked 类正好派上用场!

改造 UseResource() 函数,输出结果正式我们期望的 500000

        private static bool UseResource()
{
if (Interlocked.Exchange(ref usingResource,) == )
{
accessed++;
usingResource = ;
return true;
}
else
{
Interlocked.Increment(ref denied);
return false;
}
}

读到这里,有心的朋友可能会问,usingResource 变量为何设计成整型值?用布尔值不好吗?这正是体现整型值的灵活的地方,我们可以通过更改 UseResource() 函数的逻辑,控制统一时间可以有多少个线程访问资源,而并非只限定一个线程可以访问。

后话:

这是第二篇关于线程同步的学习笔记,其实书看得很快,但是文章却写得很慢。我发觉学习线程同步最好的方式就是设计一个反例,并更正它,确认运行结果是否与你预期的一致。在写这篇文章的过程中,我试图设计很多例子,也激发了自己很多的思考,其中有些想法开始是错的,在不断对比思考的过程里,逐渐加深认识了线程资源访问的设计。在大逻辑上,上一篇中 lock 语句会等待资源的释放,直至访问成功完成任务;而本篇中我们的线程会视图访问一些资源,不成功时我们会干别的事情,不会等待。

希望在这一系列文章写完的时候,我会对线程的同步有一个正确且深刻的认识,这也是我写这些读书笔记的目的。

C#线程同步技术(二) Interlocked 类的更多相关文章

  1. 【WIN32进阶之路】:线程同步技术纲要

    前面博客讲了互斥量(MUTEX)和关键段(CRITICAL SECTION)的使用,想来总觉不妥,就如盲人摸象一般,窥其一脚而言象,难免以偏概全,追加一篇博客查遗补漏. win32下的线程同步技术分为 ...

  2. 重新想象 Windows 8 Store Apps (46) - 多线程之线程同步: Lock, Monitor, Interlocked, Mutex, ReaderWriterLock

    [源码下载] 重新想象 Windows 8 Store Apps (46) - 多线程之线程同步: Lock, Monitor, Interlocked, Mutex, ReaderWriterLoc ...

  3. 转:C# 线程同步技术 Monitor 和Lock

    原文地址:http://www.cnblogs.com/lxblog/archive/2013/03/07/2947182.html 今天我们总结一下 C#线程同步 中的 Monitor 类 和 Lo ...

  4. iOS开发系列-线程同步技术

    概述 多线程的本质就是CPU轮流随机分配给每条线程时间片资源执行任务,看起来多条线程同时执行任务. 多条线程同时访问同一块资源,比如操作同一个对象.统一变量.同一个文件,就会引发数据错乱和数据安全的问 ...

  5. C#线程同步技术(一) lock 语句

    开篇语: 上班以后,烦恼少了,至少是没有什么好烦的了,只要负责好自己的工作就可以了,因此也有更多的时间去探索自己喜欢的程序.买回来的书已经看了一半,DEMO也敲了不少,昨晚终于在这里开BLOG,记录一 ...

  6. Delphi 线程同步技术(转)

    上次跟大家分享了线程的标准代码,其实在线程的使用中最重要的是线程的同步问题,如果你在使用线程后,发现你的界面经常被卡死,或者无法显示出来,显示混乱,你的使用的变量值老是不按预想的变化,结果往往出乎意料 ...

  7. (删)Java线程同步实现二:Lock锁和Condition

    在上篇文章(3.Java多线程总结系列:Java的线程同步实现)中,我们介绍了用synchronized关键字实现线程同步.但在Java中还有一种方式可以实现线程同步,那就是Lock锁. 一.同步锁 ...

  8. java线程池技术(二): 核心ThreadPoolExecutor介绍

    版权声明:本文出自汪磊的博客,转载请务必注明出处. Java线程池技术属于比较"古老"而又比较基础的技术了,本篇博客主要作用是个人技术梳理,没什么新玩意. 一.Java线程池技术的 ...

  9. JAVA线程同步 (二)notify()与notifyAll()-***

    编写多线程程序需要进行线程协作,前面介绍的利用互斥来防止线程竞速是来解决线程协作的衍生危害的.编写线程协作程序的关键是解决线程之间的协调问题,在这些任务中,某些可以并行执行,但是某些步骤需要所有的任务 ...

随机推荐

  1. [AGC019E]Shuffle and Swap

    [AGC019E]Shuffle and Swap 题目大意: 给出两个长度为\(n(n\le10000)\)的\(01\)串\(A_{1\sim n}\)和\(B_{1\sim n}\).两个串均有 ...

  2. [Luogu1462]通往奥格瑞玛的道路

    题目大意: 一个n个点,m条边的图,每个边有一个边权,每个点也有一个点权. 现在要找一条从1到n的路径,保证边权和不超过b的情况下,最大点权尽量小. 问最大点权最小能是多少? 思路: 二分答案,然后D ...

  3. JDK源码学习笔记——Integer

    一.类定义 public final class Integer extends Number implements Comparable<Integer> 二.属性 private fi ...

  4. zigbee控制ADAM4150

    任务名称:zigbee节点控制ADAM4150 实验现象:通过zigbee节点上的节点控制ADAM 注意点:控制ADAM4150的波特率必须是9600,否则会出现错误 核心代码 1.寄存器配置 voi ...

  5. Web安全测试指南--权限管理

    垂直权限提升: 编号 Web_Author_01 用例名称 垂直权限提升测试 用例描述 测试用户是否具有使用超越其角色范围之外的权限. 严重级别 高 前置条件 1.  目标系统拥有不同等级的角色和权限 ...

  6. C# 获取文件版本

    var versionInfo = FileVersionInfo.GetVersionInfo(filePath); String productVersion = versionInfo.Prod ...

  7. [Bug]Object reference not set to an instance of an object.

    引言 今天在客户这儿,由一个问题导致,需求的变化,不得不修改代码,在记录日志中出现该问题. 原因 通过id查找相关信息,没有判断是否为null,集合是否有数据. Object reference no ...

  8. rocketmq持久化方式

    推荐看下RocketMQ,使用文件做持久化, 并支持分布式事务(虽然可能造成较多的写脏), 异步刷盘,内存预分配, 高可用采用了同步双写及异步复制的方式, 通信是用netty做的,基本上所有耗时的操作 ...

  9. 【docker】【redis】2.docker上设置redis集群---Redis Cluster部署【集群服务】【解决在docker中redis启动后,状态为Restarting,日志报错:Configured to not listen anywhere, exiting.问题】【Waiting for the cluster to join...问题】

    参考地址:https://www.cnblogs.com/zhoujinyi/p/6477133.html https://www.cnblogs.com/cxbhakim/p/9151720.htm ...

  10. Unity3d设计模式之单例模式

    单例模式我相信是所有设计模式之中运用最广泛的设计模式之一. 今天我们就来看看在unity中如何使用单例模式,在unity中,我们分两种单例,一种是继承monobehavior的单例,一种是普通单例. ...