Interlocked.Increment()函数详解 (转载)
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()函数详解 (转载)的更多相关文章
- malloc 与 free函数详解<转载>
malloc和free函数详解 本文介绍malloc和free函数的内容. 在C中,对内存的管理是相当重要.下面开始介绍这两个函数: 一.malloc()和free()的基本概念以及基本用法: 1 ...
- kzalloc 函数详解(转载)
用kzalloc申请内存的时候, 效果等同于先是用 kmalloc() 申请空间 , 然后用 memset() 来初始化 ,所有申请的元素都被初始化为 0. view plain /** * kzal ...
- Linux中fork()函数详解(转载)
[原创地址]http://blog.csdn.net/jason314/article/details/5640969 [转载地址]http://www.cnblogs.com/bastard/arc ...
- WinMain函数详解(转载)
略加增添与修改! 工具:VC++6.0 系统:win7 64位 在Windows应用程序中,我们可以认为 WinMain() 函数是程序的入口,WinMain()的原型如下: int WI ...
- 【转载】jQuery.extend 函数详解
转载自:http://www.cnblogs.com/RascallySnake/archive/2010/05/07/1729563.html jQuery.extend 函数详解 JQuery的e ...
- 【转载】3D/2D中的D3DXMatrixPerspectiveFovLH和D3DXMatrixOrthoLH投影函数详解
原文:3D/2D中的D3DXMatrixPerspectiveFovLH和D3DXMatrixOrthoLH投影函数详解 3D中z值会影响屏幕坐标系到世界坐标系之间的转换,2D中Z值不会产生影响(而只 ...
- 【转载】C语言itoa()函数和atoi()函数详解(整数转字符C实现)
本文转自: C语言itoa()函数和atoi()函数详解(整数转字符C实现) 介绍 C语言提供了几个标准库函数,可以将任意类型(整型.长整型.浮点型等)的数字转换为字符串. int/float to ...
- Linux中fork()函数详解(转载)
linux中fork()函数详解 一.fork入门知识 一个进程,包括代码.数据和分配给进程的资源.fork()函数通过系统调用创建一个与原来进程几乎完全相同的进程,也就是两个进程可以做完全相同的事, ...
- 转载_fread函数详解
fread函数详解 函数原型: size_t fread( void *buffer, size_t size, size_t count, FILE *strea ...
随机推荐
- 【PAT甲级】1086 Tree Traversals Again (25 分)(树知二求一)
题意:输入一个正整数N(<=30),接着输入2*N行表示栈的出入(入栈顺序表示了二叉搜索树的先序序列,出栈顺序表示了二叉搜索树的中序序列),输出后序序列. AAAAAccepted code: ...
- 微信小程序媒体音乐API更新小记,以及音乐外链制作方法
假期开发微信小程序玩的时候发现音乐播放功能,但是教程中的旧版API已经不能成成功打开 官方文档写的很清楚,旧版接口不再维护,使用新版接口,换API后,又出现了新的问题,虽然没有报错信息,但是播放器闪退 ...
- 计算机二级-C语言-程序修改题-190116记录-对数组进行排序的两种方法。
//函数fun的功能是:将n个无序整数从小到大排序. //冒泡排序法:小数往下浮,大数往上浮.把数都存到一个数组,然后两两比较,大数往后交换.双层递减循环. //第二种方法:都放入一个数组中,然后记录 ...
- [BUUCTF 2018]Online Tool
进入页面 贴出源码 <?php if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) { $_SERVER['REMOTE_ADDR'] = $_SERVER ...
- Plastic Bottle Manufacturer -Plastic Bottle Forming Process
As a professional cosmetic bottle manufacturer, we know that plastic bottles are part of the rubber ...
- 实验1 GIT代码版本管理
(一)实验目的: 1)了解分布式分布式版本控制系统的核心机理: 2) 熟练掌握git的基本指令和分支管理指令: (二)实验内容: 1)安装git 2)初始配置git ,git init git sta ...
- numpy常用函数之arange函数
2.np.arange([start, ]stop, [step, ]dtype=None) 作用: arange函数用于创建等差数组 start:可忽略不写,默认从0开始;起始值 stop:结束 ...
- Vue中组件之间的通信方式
vue是数据驱动视图更新的框架, 所以对于vue来说组件间的数据通信非常重要,那么组件之间如何进行数据通信的呢? 本文会介绍组件间通信的8种方式如下图所示, 并介绍在不同的场景下如何选择有效方式实现的 ...
- Cocos纹理理解
原文:https://blog.csdn.net/u010223072/article/details/78287294 理论要点 要点一: 文件格式与像素格式的区别:文件格式是图像为了存储信息而使用 ...
- DoublyLinkedList(双向链表)
本来还不会写双向链表的,但最近学习了二叉树后,突然意识到这不就是双向链表嘛,然后通过对二叉树的理解,实现了一下双向链表. 代码: #define SIZE 10 DouLL * head, *n, * ...