原文地址

    class Program
{
static object lockObj = new object();
static int maxTask = ;
static int currentCount = ;
//假设要处理的数据源
static List<int> numbers = Enumerable.Range(, ).ToList();
static void Main(string[] args)
{
var A = numbers;
TaskContinueDemo();
Console.ReadKey();
}
private static void TaskContinueDemo()
{
while (currentCount < maxTask && numbers.Count > )
{
lock (lockObj)
{
if (currentCount < maxTask && numbers.Count > )
{
Interlocked.Increment(ref currentCount);//以原子操作的形式实现递增
var task = Task.Factory.StartNew(() =>
{
var number = numbers.FirstOrDefault();
if (number > )
{
numbers.Remove(number);
Thread.Sleep();//假设执行一秒钟
Console.WriteLine("Task id {0} Time{1} currentCount{2} dealNumber{3}", Task.CurrentId, DateTime.Now, currentCount, number);
if (Rand() == )//模拟执行中异常
{
numbers.Add(number);//因为出现异常,所以这里需要将number重新放入集合等待处理
Console.WriteLine("number {0} add because Exception", number);
throw new Exception();
}
}
}, TaskCreationOptions.LongRunning).ContinueWith(t =>
{//在ContinueWith中恢复计数
Interlocked.Decrement(ref currentCount);
Console.WriteLine("Continue Task id {0} Time{1} currentCount{2}", Task.CurrentId, DateTime.Now, currentCount);
TaskContinueDemo();
});
}
}
}
}
private static int Rand(int maxNumber = )
{
return Math.Abs(Guid.NewGuid().GetHashCode()) % maxNumber;
} }
InterLockedIncrement and InterLockedDecrement

实现数的原子性加减。什么是原子性的加减呢?

举个例子:如果一个变量 Long value =;

首先说一下正常情况下的加减操作:value+=;

:系统从Value的空间取出值,并动态生成一个空间来存储取出来的值;

:将取出来的值和1作加法,并且将和放回Value的空间覆盖掉原值。加法结束。

如果此时有两个Thread ,分别记作threadA,threadB。

:threadA将Value从存储空间取出,为0;

:threadB将Value从存储空间取出,为0;

:threadA将取出来的值和1作加法,并且将和放回Value的空间覆盖掉原值。加法结束,Value=。

:threadB将取出来的值和1作加法,并且将和放回Value的空间覆盖掉原值。加法结束,Value=。

最后Value = ,而正确应该是2;这就是问题的所在,InterLockedIncrement 能够保证在一个线程访问变量时其它线程不能访问。同理InterLockedDecrement。

LONG   InterlockedDecrement(   
      LPLONG   lpAddend       //   variable   address   
);   
属于互锁函数,用在同一进程内,需要对共享的一个变量,做减法的时候,   
防止其他线程访问这个变量,是实现线程同步的一种办法(互锁函数) 
   
首先要理解多线程同步,共享资源(同时访问全局变量的问题),否则就难以理解。   
     
result   =   InterlockedDecrement(&SomeInt)   
     
如果不考虑多线程其实就是   result   =   SomeInt   -   ;   
     
但是考虑到多线程问题就复杂了一些。就是说如果想要得到我预期的结果并不容易。   
     
result   =   SomeInt   -   ;   
     
举例说:   
SomeInt如果==;   
预期的结果result当然==;   
     
但是,如果SomeInt是一个全程共享的全局变量情况就不一样了。   
C语言的"result   =   SomeInt   -   1;"   
在实际的执行过程中,有好几条指令,在指令执行过程中,其它线程可能改变SomeInt值,使真正的结果与你预期的不一致。   
     
所以InterlockedDecrement(&SomeInt)的执行过程是这样的   
{   
      __禁止其他线程访问   (&SomeInt)   这个地址   
     
      SomeInt   --;   
         
      move   EAX,   someInt;   //   设定返回值,C++函数的返回值   都放在EAX中,   
     
      __开放其他线程访问   (&SomeInt)   这个地址   
}   
     
但是实际上只需要几条指令加前缀就可以完成,以上说明是放大的。   
     
你也许会说,这有必要吗?   一般来说,发生错误的概率不大,但是防范总是必要的 
如果不考虑多线程   
result   =   InterlockedDecrement(&SomeInt);   
就是result   =   SomeInt   -   ;   
如果SomeInt==,result一定==;   
     
但是,在多线程中如果SomeInt是线程间共享的全局变量,情况就不那么简单了。   
result   =   SomeInt   -   ;   
在CPU中,要执行好几条指令。在指令中间有可能SomeInt被线程修改。那实际的结果就不是你预期的结果了。   
     
InterlockedDecrement(&SomeInt)   
放大的过程,如下:   
{   
      __禁止其他线程访问   &SomeInt   地址;   
     
      SomeInt   --;   
         
      /////其他线程不会在这里修改SomeInt值。   !!!!!!   
     
      mov   EAX,   SomeInt;   //C++   函数返回值   总放在EAX中。   
         
      __开放其他线程访问   &SomeInt   地址;   
}   
     
实际的CPU执行过程只有几条加前缀的指令(586指令)   
     
你会说,有必要吗?   出错的概率不大,但是错误总是需要防范的。当然可以用其他多线程机制实现,但是都没有这样简洁,所以Interlocked...函数有必要提供。

Interlocked.Increment()函数详解 (转载)的更多相关文章

  1. malloc 与 free函数详解<转载>

    malloc和free函数详解   本文介绍malloc和free函数的内容. 在C中,对内存的管理是相当重要.下面开始介绍这两个函数: 一.malloc()和free()的基本概念以及基本用法: 1 ...

  2. kzalloc 函数详解(转载)

    用kzalloc申请内存的时候, 效果等同于先是用 kmalloc() 申请空间 , 然后用 memset() 来初始化 ,所有申请的元素都被初始化为 0. view plain /** * kzal ...

  3. Linux中fork()函数详解(转载)

    [原创地址]http://blog.csdn.net/jason314/article/details/5640969 [转载地址]http://www.cnblogs.com/bastard/arc ...

  4. WinMain函数详解(转载)

    略加增添与修改! 工具:VC++6.0       系统:win7 64位 在Windows应用程序中,我们可以认为 WinMain() 函数是程序的入口,WinMain()的原型如下: int WI ...

  5. 【转载】jQuery.extend 函数详解

    转载自:http://www.cnblogs.com/RascallySnake/archive/2010/05/07/1729563.html jQuery.extend 函数详解 JQuery的e ...

  6. 【转载】3D/2D中的D3DXMatrixPerspectiveFovLH和D3DXMatrixOrthoLH投影函数详解

    原文:3D/2D中的D3DXMatrixPerspectiveFovLH和D3DXMatrixOrthoLH投影函数详解 3D中z值会影响屏幕坐标系到世界坐标系之间的转换,2D中Z值不会产生影响(而只 ...

  7. 【转载】C语言itoa()函数和atoi()函数详解(整数转字符C实现)

    本文转自: C语言itoa()函数和atoi()函数详解(整数转字符C实现) 介绍 C语言提供了几个标准库函数,可以将任意类型(整型.长整型.浮点型等)的数字转换为字符串. int/float to ...

  8. Linux中fork()函数详解(转载)

    linux中fork()函数详解 一.fork入门知识 一个进程,包括代码.数据和分配给进程的资源.fork()函数通过系统调用创建一个与原来进程几乎完全相同的进程,也就是两个进程可以做完全相同的事, ...

  9. 转载_fread函数详解

    fread函数详解 函数原型: size_t   fread(   void   *buffer,   size_t   size,   size_t   count,   FILE   *strea ...

随机推荐

  1. 吴裕雄 python 神经网络——TensorFlow 三层简单神经网络的前向传播算法

    import tensorflow as tf w1= tf.Variable(tf.random_normal([2, 3], stddev=1, seed=1)) w2= tf.Variable( ...

  2. ArrayList、Vector和LinkedList

    List接口特点 1.有序的 collection. 2.可以对列表中每个元素的插入位置进行精确地控制. 3.可以根据元素的索引访问元素,并搜索列表中的元素. 4.列表通常允许重复的元素. 5.允许存 ...

  3. 吴裕雄 python 神经网络——TensorFlow 多线程队列操作

    import tensorflow as tf queue = tf.FIFOQueue(100,"float") enqueue_op = queue.enqueue([tf.r ...

  4. ElasticSearch学习记录 - 命令示例

    GET /searchfilmcomments/searchfilmcomments/_search { "query": { "match_all": {} ...

  5. MySQL中case when的基本用法总结

    MySQL中case when的基本用法总结原创Backcanhave7 最后发布于2018-12-06 15:14:15 阅读数 439 收藏展开MySQL中的case when有用两种用法,官方文 ...

  6. 基于three.js实现特定Div容器的粒子特效封装

    本文基于three.js实现特定容器的粒子特效效果,支持用户传入特定的dom对象以及粒子颜色. 效果图 移入库 <script src="jquery-1.11.3.min.js&qu ...

  7. [运维] 如何将 Linux 上的 nginx 变成 静态资源服务器 (二)

    环境 虚拟机上运行 Linux centos 7 64 已经安装 nginx-1.16.1.tar.gz  具体的安装过程可以参考 https://www.cnblogs.com/unityworld ...

  8. Python之字符

    关于字符的常用操作:(字符为不可变长度的类型,故不能“增”.“删”等改变长度的操作) 1.改:改变字符串中的某个值.但为浅改变: name = "Python3.5" print( ...

  9. Hosts工作原理及作用

    Hosts是一个没有扩展名的系统文件,可以用记事本等工具打开.其作用就是将一些常用的网址域名与其对应的IP地址建立一个关联“数据库”.当用户在浏览器中输入一个需要登录的网址时,系统会先检查系自己的Ho ...

  10. masonry使用添加紧凑、抗压属性

    // 内容紧凑 - 优先完全显示内容,且不多占像素. [self.leftLabel setContentHuggingPriority:UILayoutPriorityDefaultHigh for ...