推荐参考博客:秒杀多线程第三篇 原子操作 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. HTTP常见响应状态码

    200 : (OK) 服务器已成功处理了请求. 通常,这表示服务器提供了请求的网页. 201 : (Created) 请求成功并且服务器创建了新的资源. 301 : (Moved Permanentl ...

  2. Bootstrap案例中,登陆界面自适应

    1.html布局源码: <!DOCTYPE html><html lang="en"><head> <meta charset=" ...

  3. Nginx部署多个网站

    为节省资源,通常一个服务器会运行多个网站,通常一个服务一个IP,多个域名共用一个IP,多个域名共用一个端口(通常是80端口). 这时候需要一台服务器部署多个网站,多个网站共用一个IP,共用一个80端口 ...

  4. <转>用 Java 技术创建 RESTful Web 服务

    转自:https://www.ibm.com/developerworks/cn/web/wa-jaxrs/#N1017E JAX-RS:一种更为简单.可移植性更好的替代方式 Dustin Amrhe ...

  5. c++ primer 学习杂记2【派生类到基类转换的可访问性】

    参考: http://blog.csdn.net/rehongchen/article/details/7930853 http://blog.csdn.net/ming_road/article/d ...

  6. [Wc]Dface双面棋盘()

    题解: 一道维护奇怪信息的线段树... 我刚开始看了标签想的是删去图上一个点后求连通性 发现不会 于是退化成一般图支持删除 插入 维护连通性 发现有2两种做法 1.lct维护 按照结束顺序先后排序,给 ...

  7. BZOJ 4767 两双手

    题解: 发现这种题目虽然可以想出来,但磕磕碰碰得想挺久的 根据数学可以知道组成方案是唯一的(集合) 然后发现每个使用的大小可能是接近n^2的 直接dp(n^4)是过不了的 那么先观察观察 我们可以把每 ...

  8. python全栈开发day18-模块和导入

    1.昨日内容回顾 2.模块和模块导入 1.什么是模块,为什么要模块? py文件就是模块, 把相似的功能放到一个文件,要用的时候 引入就可以直接调用了. import py文件名,导入模块就是执行他的代 ...

  9. Codeforces 498B Name That Tune 概率dp (看题解)

    Name That Tune 刚开始我用前缀积优化dp, 精度炸炸的. 我们可以用f[ i ][ j ] 来推出f[ i ][ j + 1 ], 记得加加减减仔细一些... #include<b ...

  10. Docker 容器中无ss命令解决方法

    在早期运维工作中,查看服务器连接数一般都会用netstat命令.其实,有一个命令比netstat更高效,那就是ss(Socket Statistics)命令!ss命令可以用来获取socket统计信息, ...