一、问题

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调用构造函数初始化后,内存内容是:

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

最新文章

  1. 史上最全Windows版本搭建安装React Native环境配置
  2. iOS 10.0适配之旅
  3. express-session 保存遇到的问题
  4. python-模块安装方法
  5. 去它的h5,我还是用js写原生跨平台app吧
  6. Android 摇一摇 之 传感器片
  7. CSS3随内容自动伸缩的背景【转】
  8. 学习之痛(数据库->存储过程和函数)
  9. ASP.NET中的TextBox下划线
  10. char型变量中能存贮一个中文汉字
  11. java后台调用HttpURLConnection类模拟浏览器请求(一般用于接口调用)
  12. Qt4--加密日记本(子例化QMainWindow文本加密解密)
  13. Android Touch事件传递机制具体解释 上
  14. 将Ojective-C代码移植转换为Swift代码
  15. jquery 里 $(this)的用法
  16. maven新建的项目,不自动引入依赖包
  17. JavaScript 基本语法结构
  18. 理解C语言中几个常见修饰符
  19. Socket 异步通信
  20. spring集成shiro登陆流程(上)

热门文章

  1. 项目管理之 使用 appledoc 生成开发文档
  2. 初码-Azure系列-文章目录
  3. 在Azure China用自定义镜像创建Azure VM Scale Set
  4. 向EXECL文件中导入数据的同时插入图片
  5. C#解析json的两种方式
  6. Promise实现多图预加载
  7. intel hex 格式的几个链接
  8. 浅谈this那些事
  9. comm的用法
  10. HTML5浏览器定位navigator.geolocation.getCurrentPosition