推荐参考博客:秒杀多线程第三篇 原子操作 Interlocked系列函数

原子操作 VS 非原子操作

原子操作就是不会被线程调度机制打断的操作,这种操作一旦开始,就一直运行到结束,中间不会有任何线程切换。                                          本文地址

首先从一个简单的例子来看,1000个线程同时对一个全局变量(初始化为0)做++操作,最后我们期望的这个变量的值是1000,但是有时候结果却事与愿违:

 #include<string>
#include<iostream>
#include<process.h>
#include<windows.h>
using namespace std; volatile int g_cnt; unsigned __stdcall threadFun(void *param)
{
g_cnt++;
return 0;
} int main()
{
for(int j = 0; j < 100; j++)
{
g_cnt = 0;
const int threadNum = 1000;
HANDLE hth[threadNum]; for(int i = 0; i < threadNum; i++)
hth[i] = (HANDLE)_beginthreadex(NULL, 0, threadFun, NULL, 0, NULL); //注意WaitForMultipleObjects每次最多等待MAXIMUM_WAIT_OBJECTS个object;
//也可以调用1000次WaitForSingleObject
int k = threadNum / MAXIMUM_WAIT_OBJECTS;
for(int i = 0; i < k; i++)
WaitForMultipleObjects(MAXIMUM_WAIT_OBJECTS,
&hth[i*MAXIMUM_WAIT_OBJECTS],
TRUE, INFINITE);
if(threadNum % MAXIMUM_WAIT_OBJECTS != 0)
WaitForMultipleObjects(threadNum % MAXIMUM_WAIT_OBJECTS,
&hth[k*MAXIMUM_WAIT_OBJECTS],
TRUE, INFINITE); for(int i = 0; i < threadNum; i++)
CloseHandle(hth[i]); if(g_cnt != 1000)
cout<<"the value of g_cnt: "<<g_cnt<<endl;
}
}

为什么会这样呢,因为g_cnt++不是一个原子操作,在vs2010中查看反汇编代码为:

对于++操作,编译器把它分为三步:1、从内存中吧g_cnt的值读到寄存器eax,2、eax中的值+1, 3、把eax中的值写会内存

如果有两个线程,线程1执行到第二条语句时,线程2开始执行,那么线程2获取的g_cnt的值还是原来的0(因为线程1还没有执行低三条语句来写回内存),最后g_cnt的值就是1,而不是期望的2;

windows系统提供给了一些函数来保证某些操作的原子性:

LONG __cdecl InterlockedIncrement(LONG volatile* Addend); //变量加1

LONG __cdecl InterlockedDecrement(LONG volatile* Addend);//变量减1

LONG __cdec InterlockedExchangeAdd(LONG volatile* Addend, LONG Value);//变量加上value

LONG __cdecl InterlockedExchange(LONG volatile* Target, LONG Value);//将value的值 赋值 给target指向的变量

以上列出的函数是针对32位的LONG数据的,如果是64位的数据,有其对应的函数,具体可以参考 msdn 列出的所有原子操作函数

针对上面的问题,我们可以把g_cnt++; 改为 InterlockedIncrement((LONG volatile *)&g_cnt);

【版权声明】转载请注明出处:http://www.cnblogs.com/TenosDoIt/p/3602426.html

windows多线程--原子操作的更多相关文章

  1. 总结windows多线程同步互斥

    windows多线程同步互斥--总结 我的windows多线程系列文章: windows多线程--原子操作 windows多线程同步--事件 windows多线程同步--互斥量 windows多线程同 ...

  2. windows多线程同步互斥--总结

    我的windows多线程系列文章: windows多线程--原子操作 windows多线程同步--事件 windows多线程同步--互斥量 windows多线程同步--临界区 windows多线程同步 ...

  3. windows多线程编程星球(一)

    以前在学校的时候,多线程这一部分是属于那种充满好奇但是又感觉很难掌握的部分.原因嘛我觉得是这玩意儿和编程语言无关,主要和操作系统的有关,所以这部分内容主要出现在讲原理的操作系统书的某一章,看完原理是懂 ...

  4. Windows多线程多任务设计初步(转)

    Windows多线程多任务设计初步 [前言:]当前流行的Windows操作系统,它能同时运行几个程序(独立运行的程序又称之为进程),对于同一个程序,它又可以分成若干个独立的执行流,我们称之为线程,线程 ...

  5. windows多线程没那么难

    windows多线程没那么难 作者:vpoet mail:vpoet_sir@163.com 上一博文中我们引入了CreateThread()多线程编程一个简单的例子,事实上我说windows 多线程 ...

  6. Windows多线程

    //简单的引出多线程是肿么回事儿....当点击下载的时候,下载内容还没结束也可以点击资源库,其实这就用了另一个线程,弹出“下载完成”对话框的时候,没有点击确定是不能点击主页面内容的,这就是用----- ...

  7. Windows多线程学习随笔

    自学Windows多线程知识,例程如下: #include <iostream> #include <windows.h> #include <process.h> ...

  8. windows多线程同步--临界区

    推荐参考博客:秒杀多线程第五篇 经典线程同步 关键段CS   关于临界区的观念,一般操作系统书上面都有. 适用范围:它只能同步一个进程中的线程,不能跨进程同步.一般用它来做单个进程内的代码快同步,效率 ...

  9. windows多线程接口介绍和使用

    一windows多线程接口: 1 创建线程 CreateThread 与 _beginthreadex都可以实现创建线程,两个函数的参数 相同, HANDLEWINAPICreateThread( L ...

随机推荐

  1. hdu3397区间覆盖,区间翻转,区间合并,区间求和

    调了很久的代码..注意区间翻转和覆盖的操作互相的影响 /* 区间替换操作怎么搞? 应该是加个tag标记 如果整个区间都是0|1,那么把若有tag的话直接set1|0即可,也不用设置tag标记 反之要设 ...

  2. python接口自动化测试六:时间戳,防重复处理

    对于不可重复参数,可以用时间戳,防重复 import time title = '这是我的标题:%s'%str(int(time.time())) print(title) 转化成时间格式 t = t ...

  3. python 全栈开发,Day88(csrf_exempt,ES6 快速入门,Vue)

    BBS项目内容回顾 1. 登陆页面 1. 验证码 1. PIL(Pillow) 2. io 2. ORM 1. 增删改查 3. AJAX $.ajax({ url: '', type: '', dat ...

  4. jvm类加载器以及双亲委派

    首先来了解几个概念: 类加载: 概念:虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验--转换解析--初始化,最终形成能被java虚拟机直接使用的java类型,就是jvm的类加载机制. ...

  5. 《剑指offer》-栈的压入、弹出序列

    输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否为该栈的弹出顺序.假设压入栈的所有数字均不相等.例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一 ...

  6. C#检查服务状态和启动关闭服务

    WinForm 判断服务状态,显示服务名称和状态 https://blog.csdn.net/u013063880/article/details/78626200 C#获得服务,判断服务状态,启动服 ...

  7. python 线程间通信之Condition, Queue

    Event 和 Condition 是threading模块原生提供的模块,原理简单,功能单一,它能发送 True 和 False 的指令,所以只能适用于某些简单的场景中. 而Queue则是比较高级的 ...

  8. mac和Linux的环境变量设置

    摘抄自:http://hi.baidu.com/machao_pe/item/763d0ef12d32cd35fe3582db redhat和ubuntu中修改环境变量 2010-03-06 23:4 ...

  9. 10.Django用户认证组件

    用户认证组件: 功能:用session记录登录验证状态: 前提:用户表,django自带的auth_user 创建超级用户:python manage.py createsuperuser       ...

  10. tensorflow 使用CPU而不使用GPU的问题解决

    今天发现一个怪现象,在训练keras时,发现不使用GPU进行计算,而是采用CPU进行计算,导致计算速度很慢. 用如下代码可检测tensorflow的能使用设备情况: from tensorflow.p ...