推荐参考博客:秒杀多线程第三篇 原子操作 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. 性能测试二十五:redis-cli 命令总结

    常用命令dbsize:查看redis中的kv数量 keys *:查看redis中所有的keyset key_1 v_1:新增一个key_1,包含v_1get key_1:查看key_1中的内容del ...

  2. asp.net core 微信公众号支付(扫码支付,H5支付,公众号支付,app支付)之3

    在微信公众号中访问手机网站,当需要调用支付时候无法使用H5支付,只有使用微信公众号支付,使用公众号支付用户必须关注该公众号同时该公众号必须开通公众号支付功能. 1.获取用户的OpenId ,参考之前写 ...

  3. 045 介绍UDF,以及完成大小写的转换

    一:概述 1.UDF 用户自定义函数,用java实现自定义的需求 User Defined Function-----UDF. 2.UDF的类型 udf:一进一出 udaf:多进一出 udtf:一进多 ...

  4. Enrolment API

    由于Moodle 2.0有一个用户注册的新概念,它们完全独立于角色和功能.能力通常与注册状态结合使用. 什么是注册? 登记的用户可以完全参加一门课程.活跃用户注册允许用户输入课程.只有注册的用户可能是 ...

  5. mac下配置Apache虚拟域名方案,以及遇到的坑(转)

      1. 配置Apache虚拟域名 1.执行    sudo vi /etc/apache2/httpd.conf 开始配置httpd.conf 的文件; //配置listen 80端口(默认配置), ...

  6. docker容器中安装vim 、telnet、ifconfig, ping命令

    在使用docker容器时,有时候里边没有安装vim,敲vim命令时提示说:vim: command not found,这个时候就需要安装vim,可是当你敲apt-get install vim命令时 ...

  7. 洛谷 p1044 栈 【Catalan(卡特兰数)】【经典题】

    题目链接:https://www.luogu.org/problemnew/show/P1044 转载于:https://www.luogu.org/blog/QiXingZhi/solution-p ...

  8. Ubuntu 初始配置

      1)在修改source.list前,最好先备份一份 sudo cp /etc/apt/sources.list /etc/apt/sources.list_backu2. 2)执行命令打开sour ...

  9. P1862输油管道问题

    P1862输油管道问题. . . . .-----------------. . . . . .图像大体是这样,是带权平均数问题,设答案是k,sigama(abs(yi-k*wi))最小,这里的wi是 ...

  10. Java开发人员必须掌握的两个Linux魔法工具(四)

    子曰:"工欲善其事,必先利其器." 做一个积极的人 编码.改bug.提升自己 我有一个乐园,面向编程,春暖花开! 学习应该是快乐的,在这个乐园中我努力让自己能用简洁易懂(搞笑有趣) ...