静态变量在不同模块上共享价值
Static variables share value across different modules
第一个问题上下文:Linux X64,GCC v4.8.5。有一个应用程序加载两个共享库(让它为Module1.so和Module2.SO),这些模块具有部分相同的代码。现在一点代码:
//SomeClass.h
class SomeClass
{
public:
static unsigned long& s_uObj2()
{
static unsigned long s_uObj2;
return s_uObj2;
};
void Initialize();
};
//SomeClass.cpp
void SomeClass::Initialize()
{
if (0 == s_uObj2())
{
//do init
}
s_uObj2()++; //acts as a counter
}
此代码已经很久以前编写,它的想法是防止每个模块中的someclass的双重初始化。问题:此实现以某种方式共享不同模块(在单个应用程序中)的S_UOBJ2值,这导致了以下事实:仅将初始化第一个模块。
那怎么可能?我认为应该隔离不同模块之间的地址空间?
请不要指出"静态变量如何工作"的一些一般案例定义。我真正需要的 - 分析为什么不同的模块在这种确切情况下共享单个变量的值。那是因为它是真实的项目,我无法重构以使其正常工作。
问题:此实施以某种方式共享S_UOBJ2值跨不同模块(在单个应用程序中),这导致了以下事实:
那怎么可能?我认为应该是隔离的地址空间在不同的模块之间?
这是C 标准的一个定义规则要求。该规则基本上说,所有具有相同名称的全局对象都必须在整个程序中解析为单个定义。例如,所有全局变量(包括类似于您的案例)必须解析到同一单个对象。
现在,GCC非常努力地保留所有共享库中的ODR。如果您在代码上方构建并检查其导出的符号,则可以看到它导出SomeClass::s_uObj2
:
$ g++ tmp.cpp -shared -fPIC && objdump -T a.out | c++filt
...
0000000000200970 w DO .bss 0000000000000008 Base SomeClass::s_uObj2()::s_uObj2
这意味着在启动时,动态链接器将把SomeClass::s_uObj2()::s_uObj2
的所有重复副本解析为 single 对象(这是恰好已加载的第一个共享库中的副本)。
克服此问题的通常方法(如果您真的愿意放弃ODR,那是不好的,那是不好的)是避免从图书馆导出s_uObj2
,即限制其可见性。
有很多方法可以做到这一点,我只列举几个:
用
编译-fvisibility-inlines-hidden
将
__attribute__((visibility("hidden")))
附加到s_uObj2
的定义将您的类声明放入
中#pragma GCC visibility push(hidden)
...
#pragma GCC visibility pop
第一个是讨厌的,因为它将有效地禁用所有代码的ODR,而不仅仅是上面的摘要。后两个更细粒度。
- 将成员变量添加到共享库中的类中,不会破坏二进制兼容性吗
- 尝试导入pybind-opencv模块时出现libgtk错误
- 是否可以通过C++扩展强制多个python进程共享同一内存
- 在cuda线程之间共享大量常量数据
- 如何从具有移动语义的类对象中生成共享指针
- Cmake 查找模块用于区分共享库或静态库
- Apache HTTPD模块共享内存权限拒绝了错误
- Python - 导入 c++ 模块接口 - 无法打开共享对象文件
- 静态变量在不同模块上共享价值
- 是否可以在本机C++模块之间共享数据
- 如何在插件 [模块] 之间共享 boost::asio::io_service
- Python C 接口,不同的模块共享静态变量
- 在一个共享对象中提升 python 多个模块
- 如何将静态或共享库链接到内核模块
- 仅检查共享库(例如 Apache 模块)中的内存问题
- 如何打包python模块所依赖的共享对象
- c++在模块间共享数组元素,仅对少数字段具有const性
- 在用SWIG编译的c和lua模块之间共享数据指针
- 如何在Python中编译、创建共享库和导入c++ boost模块
- Apache模块共享内存对象