设为首页 加入收藏

TOP

实现单实例多线程安全API问题(二)
2014-03-10 12:51:56 来源: 作者: 【 】 浏览:196
Tags:实现 实例 线程 安全 API 问题

  从上图的汇编指令可以看到static对象的构造函数是否被执行的判断逻辑:

  1、通过标识值判断是否该执行构造函数(这里的构造函数内联了);

  2、执行构造函数,首先把标志值置位。

  有可能多个线程都同时通过了1的判断,导致构造函数被多次执行。

  使用了全局对象之后发现也不可行:导出函数依赖全局对象的初始化,虽然全局对象会在main函数之前初始化,但初始化时机还是可能太晚了,譬如这种情况:lib的使用者也定义了全局对象,并且初始化得更早,使用者的全局对象构造函数里调用了lib的导出函数,导出函数使用了还没初始化的临界区全局对象导致崩溃,更麻烦的是,使用者的dump捕获机制是在main函数里初始化的,生效得太晚,导致dump无法捕获,使这个crash更加隐蔽。C++的全局对象应该尽量少用。exe里面如果使用了全局对象,则需要保证dump捕获机制对所有的代码都生效。

  既然临界区初始化问题无法解决,局部static对象、全局对象都无法使用,需要找到一个不需要初始化又能实现锁的方法:那就是原子操作。

  单纯的原子操作并没有锁的功能,需要配合上:if + Sleep.

  代码如下:

  SingleInstance* volatile g_instance;

  LONG volatile g_for_lock;

  SingleInstance* GetInstance()

  {

  if (g_instance == NULL)

  {

  LONG pre_value = ::InterlockedExchange(&g_for_lock, 1);

  if (pre_value != 0)

  {

  while(g_instance == NULL)

  {

  ::Sleep(55);

  }

  }

  if (g_instance == NULL)

  {

  g_instance = new SingleInstance;

  }

  }

  return g_instance;

  }

  全局的g_for_lock在PE文件装入内存时就初始化为0,所以不存在初始化问题;InterlockedExchange 适用于xp、win7、win8,不存在系统限制;多个线程同时调用InterlockedExchange,只能有一个线程得到0,保证只初始化一次,其余线程进入while循环等待,直到g_point非空。问题不逼你,你就不会想到还有这么好的实现思路 :)

  使用原子操作还可以很容易的实现临界区锁的功能,这里就不说了。

  三、PE文件中的Lib库全局变量

  像上边定义的全局变量,如果DLL和EXE都使用这个lib,它们各自有一份独立的全局变量。

      

首页 上一页 1 2 3 下一页 尾页 2/3/3
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇gcc编译过程简述 下一篇C++结构体的字节对齐规则

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容:

·HTTPS 详解一:附带 (2025-12-26 02:20:37)
·TCP/IP协议到底在讲 (2025-12-26 02:20:34)
·TCP和UDP在socket编 (2025-12-26 02:20:32)
·有没有适合新手练习 (2025-12-26 01:48:47)
·用清华镜像网怎么下 (2025-12-26 01:48:44)