Interlocked原子函数陷阱

时间:2023-02-25 00:02:46

一、问题

windows api函数中提供了InterlockedExchange、InterlockedDecrement, InterlockedIncrement, ExInterlockedAddLargeInteger, ExInterlockedAddUlong等原子访问函数,在众多线程同步方法中效率最高。

最近在工作中,在类A中添加了两个变量作为标志位,用于多线程间的标志同步用,所以用到了InterlockedExchange函数,类似如下代码:

//.h文件
class A{
public:
void SetFirstFlag(const bool &flag);//设置标志位a
bool GetFirstFlag();//获取标志a的值 void SetSecondFlag(const bool& flag);//设置标志位b
bool GetSecondFlag();//获取标志b的值
private:
bool a;
bool b;
}; //.cpp文件
A::A(void){
a = true;
b = true;
}
A::~A(void){ } void A::SetFirstFlag(const bool& flag){//设置标志位a
InterlockedExchange((unsigned long*)&a, flag);
} bool A::GetFirstFlag(){//获取标志a的值
if (InterlockedExchange((unsigned long*)&a, false) == true)
{
SetFirstFlag(true);//恢复为原来的值
return true;
} return false;
}
void A::SetSecondFlag(const bool& flag){//设置标志位b
InterlockedExchange((unsigned long*)&b, flag);
} bool A::GetSecondFlag(){//获取标志b的值
if (InterlockedExchange((unsigned long*)&b, false) == true)
{
SetSecondFlag(true);//恢复为原来的值
return true;
} return false;
}

这个类实现的功能很简单,调用SetFirstdFlag或者SetSecondFlag用于设置a或者b的值,调用GetFirstFlag或者GetSecondFlag获取a或者b的值。

但是在实际调试过程中发现,明明在构造函数函数中设置了a为true,但是在第一次进入到相应的SetSecondFlag或者GetSecondFlag函数中时,却发现b的值为false,而且完全不受控制,一会儿true一会儿为false,搞的我都怀疑人生了。

在耽误了一下午后,发现问题出在了指针操作上。在win32下,bool型占用1字节数据,a和b在内存上相邻,各占用1字节,在类A调用构造函数初始化后,内存内容是:

Interlocked原子函数陷阱

a和b的值都是1,但是这里函数InterlockedExchange的实际定义是:

FORCEINLINE
unsigned long
InterlockedExchange(
__inout __drv_interlocked unsigned long volatile *Target,
__in unsigned long Value
)
{
return (unsigned long) InterlockedExchange((volatile long*) Target, (long) Value);
}

很明显,被改变的变量是以long指针操作修改值的,所以每次调用InterlockedExchange((unsigned long*)&a, false)时,是将a的值赋值给了a的地址指向的4字节内存,所以b的值也被篡改了,但是修改b的值不会影响a的值。

到这里,很明显,是调用api函数的时候没注意传入参数的含义,也没注意数据类型占用的字节数导致该问题。将类A中将所有bool修改为BOOL后,因为BOOL和long都是占用4字节内存,问题就得以解决了。

二、总结

在调用api函数的时候一定要注意参数含义,尤其是指针操作的时候,要注意参数占用字节数,调用方式错误,轻则导致数据逻辑错误,重则软件崩溃。

Interlocked原子函数陷阱的更多相关文章

  1. 读书笔记——Windows核心编程(8)Interlocked系列函数

    先让我们来复习下小学知识 A+B=C//式中A为被加数,B为加数. A-B=C//式中A为被减数,B为减数. 再让我们来明确一个知识点:返回值为void的Windows函数意味着一定会执行成功. -- ...

  2. 原子操作 Interlocked系列函数

    上一篇<多线程第一次亲密接触 CreateThread与_beginthreadex本质区别>中讲到一个多线程报数功能.为了描述方便和代码简洁起见,我们可以只输出最后的报数结果来观察程序是 ...

  3. &lpar;转&rpar;原子操作 Interlocked系列函数

    上一篇<多线程第一次亲密接触 CreateThread与_beginthreadex本质区别>中讲到一个多线程报数功能.为了描述方便和代码简洁起见,我们可以只输出最后的报数结果来观察程序是 ...

  4. 多线程笔记--原子操作Interlocked系列函数

    前面写了一个多线程报数的功能,为了描述方便和代码简洁起见,只输出最后的报数结果来观察程序运行结果.这非常类似一个网站的客户访问统计,每个用户登录用一个线程模拟,线程运行时将一个表示计数的变量递增.程序 ...

  5. 多线程面试题系列(3):原子操作 Interlocked系列函数

    上一篇中讲到一个多线程报数功能.为了描述方便和代码简洁起见,我们可以只输出最后的报数结果来观察程序是否运行出错.这也非常类似于统计一个网站每天有多少用户登录,每个用户登录用一个线程模拟,线程运行时会将 ...

  6. &lbrack;Go&rsqb; golang原子函数锁住共享资源

    1.atomic包里的几个函数以及sync包里的mutex类型,提供了解决方案2.原子函数能够以很底层的加锁机制来同步访问整型变量和指针3.atomic.AddInt64(&counter, ...

  7. 秒杀多线程第三篇 原子操作 Interlocked系列函数

    上一篇<多线程第一次亲密接触 CreateThread与_beginthreadex本质区别>中讲到一个多线程报数功能.为了描述方便和代码简洁起见,我们可以只输出最后的报数结果来观察程序是 ...

  8. &lbrack;OS&rsqb; 多线程--原子操作 Interlocked系列函数

    转自:http://blog.csdn.net/morewindows/article/details/7429155 上一篇<多线程--第一次亲密接触 CreateThread与_begint ...

  9. 多线程--原子操作 Interlocked系列函数

    [转]原文地址:http://blog.csdn.net/morewindows/article/details/7429155 线程同步与互斥: 互斥主要指多个线程不能同时访问一个资源,如打印机就是 ...

随机推荐

  1. JS设计模式--简单工厂模式

    在JS中创建对象会习惯的使用new关键字和类构造函数(也是可以用对象字面量). 工厂模式就是一种有助于消除两个类依赖性的模式. 工厂模式分为简单工厂模式和复杂工厂模式,这篇主要讲简单工厂模式. 简单工 ...

  2. 基本概率分布Basic Concept of Probability Distributions 5&colon; Hypergemometric Distribution

    PDF version PMF Suppose that a sample of size $n$ is to be chosen randomly (without replacement) fro ...

  3. Android百度地图开发-第一篇:申请、搭建百度地图

    一.前言 这是第一篇关于Android使用百度地图的学习记录,主要记录: 1.在百度地图开发者平台上申请API Key. 2.在自己的应用中加入百度地图的Android版SDK. 3.在自己的应用中显 ...

  4. win10下Anaconda 2 和 3 共存安装,并切换jupyter notebook和Pycharm中的对应版本

    win10下Anaconda 2 和 3 共存安装,并切换jupyter notebook和Pycharm中的对应版本 zoerywzhou@163.com http://www.cnblogs.co ...

  5. Spring boot 的自动配置

    Xml 配置文件 日志 Spring Boot对各种日志框架都做了支持,我们可以通过配置来修改默认的日志的配置: #设置日志级别 logging.level.org.springframework=D ...

  6. &lbrack;c&sol;c&plus;&plus;&rsqb; programming之路(23)、字符串(四)——strncat,atoi,strcmp,strlen等,以及常用内存函数

    一.strncat及自行封装实现 #define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<stdlib.h> #i ...

  7. &lbrack;转&rsqb;WordPress&OpenCurlyDoubleQuote;添加媒体”文件时只显示上传到当前文章的附件图片

    使用WordPress的朋友应该都清楚,特别是喜欢图文并茂的网站,肯定离不开的就是WordPress文章编辑页面的“添加媒体”按钮,每次点击就能弹出一个插入多媒体的界面,然后页面默认就会列举加载所有最 ...

  8. 【Linux】文件夹及作用说明

    Tips Linux关机注意事项: 远程重启服务前,先停止相关服务 使用安全命令重启shutdown –r now,该命令在重启时会正常保存和终止服务器上正在运行的程序 不建议在本地直接对远程服务器关 ...

  9. SpringCloud组件和概念介绍1

    一:什么是微服务(Microservice) 微服务英文名称Microservice,Microservice架构模式就是将整个Web应用组织为一系列小的Web服务.这些小的Web服务可以独立地编译及 ...

  10. Maya学习笔记

    软件: Maya 2016 : 参考教材: Maya 2016 中文版标准教程 ; 改变视图颜色 [窗口]|[设置/首项选择]|[颜色设置]|[3D视图]: 观察视图 旋转视图 Alt + 鼠标左键 ...