接昨天谈及的线程同步问题,今天介绍一个比较简单的类,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. [转]SSH包全解

    Struts2 Core Libraries 必须引入的包 : struts2-core.jar——Struts2的核心包 xwork-core.jar——Command模式框架,WebWork和St ...

  2. hdu1428漫步校园

    #include <queue> #include <iostream> #include <algorithm> #include <cstring> ...

  3. 给XC2440开发板烧写程序的N种方式

    转:http://blog.chinaunix.net/uid-22030783-id-3420080.html 给XC2440开发板烧写程序非常灵活,总结起来有这么几种方式:   空片烧写(flas ...

  4. loadrunner的Analysis怎么生成word、ppt、html形式报告

    原文:http://jingyan.baidu.com/article/03b2f78c1936d25ea237ae0f.html 在进行使用loadrunner中进行压力测试之后就会在Analysi ...

  5. JCA 了解

    JCA (J2EE 连接器架构,Java Connector Architecture)是对 J2EE标准集的重要补充.因为它注重的是将 Java程序连接到非Java程序和软件包中间件的开发.连接器特 ...

  6. iOS: 工具栏控件UIToolBar和工具栏按钮控件UIBarButtonItem的使用

    一.工具栏控件:UIToolBar:UIView 介绍: ToolBar工具栏是视图View的属性,可以在工具栏上添加工具栏按钮Bar Button Item(可以是自定义的Custom.也可以是系统 ...

  7. 两款工控控件对比评测:Iocomp和ProEssentials

    对于程序员来说,要凭一己之力开发出漂亮逼真的工控仪表和工控图表是非常耗时间和精力的,那么使用专业的第三方控件就是不错的选择,不仅节约开发时间,降低了项目风险,最重要的是第三方控件写的程序更专业,工控图 ...

  8. android 开源项目集合

    http://p.codekk.com/ http://www.apkbus.com/code.php http://androidxref.com/ https://www.androidos.ne ...

  9. 【转】dependency injection 的例子

    Dependency Injection in PHP. Create your own DI container. / blog / PHP By my opinion one of the big ...

  10. java线程总结(3/5)

    一.线程同步和死锁问题 异步问题: package com.horizon.action; /** * 测试同步问题 * */ public class TestSync { public stati ...