原文地址

    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. 配置Nexus Tacacs管理

    1.设备拓扑: N7K(mgmt0)----VMnet1-----ACS5.2 2.设备配置:2.1.基础配置第一部分:N7Kinterface mgmt0 vrf member management ...

  2. 定位布局 Stack 层叠组件 Stack 与 Align Stack 与 Positioned 实现

    一.Flutter Stack 组件 Stack 表示堆的意思,我们可以用 Stack 或者 Stack 结合 Align 或者 Stack 结合 Positiond 来实现页面的定位布局 align ...

  3. 计算机二级-C语言-程序填空题-190117记录-对文件的处理,复制两个文件,往新文件中写入数据。

    //给定程序的功能是,调用函数fun将指定源文件中的内容赋值到指定目标文件中,复制成功时函数返回1,失败时返回0,把复制的内容输出到终端屏幕.主函数中源文件名放在变量sfname中,目标文件名放在变量 ...

  4. 【代码学习】PYTHON中的静态方法和类方法

    一.类方法 是类对象所拥有的方法,需要用修饰器@classmethod来标识其为类方法,对于类方法,第一个参数必须是类对象,一般以cls作为第一个参数(当然可以用其他名称的变量作为其第一个参数,但是大 ...

  5. Java判断对象是否为Null/空

    package com.taiping.test; import java.lang.reflect.Field; import java.lang.reflect.Type; /** * <p ...

  6. ANSYS 非线性材料模型简介1 ---常用弹塑性模型

    目录 1. 材料非线性 2. 三个准则 2.1 屈服准则 2.2 流动准则 2.3 强化准则 3. 常用弹塑性模型 3.1 双线性等向强化 3.2 多线性等向强化 3.3 非线性等向强化 3.4 双线 ...

  7. mark mark mark

    编译并使用静态lib---->>>>转自:Walkthrough: Creating and Using a Static Library (C++) 跟踪内存分配:http: ...

  8. 再次立个flag

    今天2019.9.18 从上次迷茫到现在,差不多过去快一年了.   准确点是 442 天 我顺便大概看了一下上次迷茫时期的日志,总觉的不可思议.上次是毕业大概几个月,到目前其实也没多久,但是我变了.. ...

  9. 02使用GitHub远程仓库

    一.远程库配置 由于本地的GIT仓库和GitHub仓库之间的传输是通过SSH加密的,所以需要以下配置: 1.创建SSH key 为什么GitHub需要SSHKey:根据key来授权,有哪些key可以往 ...

  10. 概念 - 抖脚(Fidgeting)

    参考 https://cn.nytimes.com/health/20161220/why-fidgeting-is-good-medicine/dual/ https://baike.baidu.c ...