用mn查看单例模式符号表——动态加载的动态链接库中的单例

nm - display name list(symbol table)

问题

有一个疑问由来已久,单例分单线程安全,多线程安全。那么如果动态加载链接库,单例还能保证只存在唯一实例吗?
于是,打算写代码验证一下

验证

1. 代码准备

总共有三个文件singleton.h, operation.cpp, main.cpp,内容如下

singleton.h
#ifndef SINGLETON_H
#define SINGLETON_Hclass Singleton{
public:Singleton(const Singleton&) = delete;Singleton& operator=(const Singleton&) = delete;static Singleton* instance() {static Singleton s;return &s;}int count;
private:Singleton(): count(0) {};
};#endif
operation.cpp
#include "singleton.h"#include <iostream>extern "C" void operation() {std::cout << "In dll count(d1): " << (Singleton::instance()->count) << std::endl;++ Singleton::instance()->count;std::cout << "In dll after ++ count(d2) : "<< (Singleton::instance()->count) << std::endl;
}
main.cpp
#include "singleton.h"#include <iostream>
#include <dlfcn.h>int main() {Singleton::instance()->count = 100;    std::cout << "In main count(m1): " << Singleton::instance()->count << std::endl;void* handle = dlopen("./operation.so", RTLD_LAZY);typedef void (*operationFunc)();operationFunc hello = (operationFunc) dlsym(handle, "operation");hello();std::cout << "In main count(m2): " << Singleton::instance()->count << std::endl;dlclose(handle);
}

2. 编译运行

在程序执行前可以先分析一下count(d1), count(d2), count(m1), count(m2)会分别是多少呢?
我们简单写一个Makfile方便编译执行

main: main.cpp operation.so$(CXX) $(CXXFLAGS) -o main main.cpp -ldl
operation.so: operation.cpp$(CXX) $(CXXFLAGS) -shared -fPIC -o operation.so operation.cpp
clean:rm -f main operation.so
.PHONY: clean

编译执行结果如下

$ make
g++  -shared -fPIC -o operation.so operation.cpp
g++  -o main main.cpp -ldl$ ./main
In main count(m1): 100
In dll count(d1): 0
In dll after ++ count(d2) : 1
In main count(m2): 100

3. 结果分析

很明显,count(d1)=0; count(d2)=1; count(m1)=100; count(m2)=100;
这说明main函数中的Singleton::instance()->count = 100; 仅对count(m1),count(m2)有效;operation中的++ Singleton::instance()->count;仅对count(d1), count(d2)有影响。即main中和动态库(operation)中,分别拥有自己实例,单例没有保证实例的唯一性

我们接着进一步分析:
用nm查看main的符号表和动态符号表(-D)

$ nm -C main | grep Singleton
0000000000012028 u guard variable for Singleton::instance()::s
0000000000000d5c W Singleton::instance()
0000000000000dd4 W Singleton::Singleton()
0000000000000dd4 W Singleton::Singleton()
0000000000012020 u Singleton::instance()::s$ nm -C -D main | grep Singleton
$

动态符号表中没有与Singleton相关的符号。Singleton::instance()在静态符号表中存在,但在动态表中不存在,这也就是说,动态连接器(dynamic linker)在加载operation.so的时候,无法找到属于动态库的Singleton::instance()实例,只能再构造一个新的实例。动态库的实例在动态库中是唯一的,但是不能保证在main和operation.so中唯一。

所以,解决问题的关键在于如何让动态库暴露符号表,让动态链接器链接的时候可以检测到。答案就是链接的时候加上参数-rdynamic

main: main.cpp operation.so$(CXX) $(CXXFLAGS) -o main main.cpp -ldl -rdynamic
operation.so: operation.cpp$(CXX) $(CXXFLAGS) -shared -fPIC -o operation.so operation.cpp
clean:rm -f main operation.so
.PHONY: clean

修改后再编译执行

$ make
g++  -shared -fPIC -o operation.so operation.cpp
g++  -o main main.cpp -ldl -rdynamic$ ./main 
In main count(m1): 100
In dll count(d1): 100
In dll after ++ count(d2) : 101
In main count(m2): 101

此时,单例便能保证实例的唯一性
我们再来查看符号表

$ nm -C main | grep Singleton
0000000000012028 u guard variable for Singleton::instance()::s
00000000000010bc W Singleton::instance()
0000000000001134 W Singleton::Singleton()
0000000000001134 W Singleton::Singleton()
0000000000012020 u Singleton::instance()::s$ nm -C -D main | grep Singleton
0000000000012028 u guard variable for Singleton::instance()::s
00000000000010bc W Singleton::instance()
0000000000001134 W Singleton::Singleton()
0000000000001134 W Singleton::Singleton()
0000000000012020 u Singleton::instance()::s

可以发现动态符号表也把所有的符号暴露出来了

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/863149.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数据结构-分析期末选择题考点(图)

我是梦中传彩笔 欲书花叶寄朝云 目录 图的常见考点&#xff08;一&#xff09;图的概念题 图的常见考点&#xff08;二&#xff09;图的邻接矩阵、邻接表 图的常见考点&#xff08;三&#xff09;拓扑排序 图的常见考点&#xff08;四&#xff09;关键路径 图的常见考点&#x…

c语言实现贪吃蛇小游戏

源码 /** * FileName: snakec* Author:PowerKing * Version&#xff1a;V1.0* Date:2024.6.28* Description: 贪吃蛇小游戏*/#include <curses.h> #include <stdlib.h> #include <pthread.h> #include <unistd.h>/*贪吃蛇游戏 */#define UP 1…

c++ 递归

递归函数是指在函数定义中调用自身的函数。C语言也支持递归函数。 下面是一个使用递归函数计算阶乘的例子&#xff1a; #include <iostream> using namespace std;int factorial(int n) {// 基本情况&#xff0c;当 n 等于 0 或 1 时&#xff0c;阶乘为 1if (n 0 || n…

S32K3 工具篇2:如何在S32DS中使用Segger JLINK下载

S32K3 工具篇2&#xff1a;如何在S32DS中使用Segger JLINK下载 一&#xff0c; S32DS中JLINK下载1.1 Segger JLINK 驱动1.2 S32DS JLINK驱动路径配置1.3 S32DS JLINK debug configuration1.4 S32DS JLINK debug S32K3板子结果 二&#xff0c; JLINK驱动实现S32K344代码下载2.1 …

mysql数据库备份-使用自带工具mysqldump备份工具,mysqlimport/source导入工具

MysqlLimport介绍 MySCLimport是MysQL数据库中的一个命令行工具&#xff0c;用于将数据从外部文件导入MySQL数据库中的表中。它可以导入多种格式的数据&#xff0c;包括CSV、TXT、XML和SQL文件等。本文将介绍MySQLimport的用法&#xff0c;并通过代码示例演示如何使用它来导入…

高考落幕,暑期西北行,甘肃美食等你来尝

高考结束&#xff0c;暑期来临&#xff0c;西北之旅成为许多人的热门选择。而来到甘肃&#xff0c;除了领略壮丽的自然风光和深厚的历史文化&#xff0c;甘肃特产和传统面点以其独特的风味和传统的制作工艺也为游客们带来了一场地道的甘肃美食体验。 平凉的美食&#x…

c++ try 函数

在C中&#xff0c;try函数用于捕获和处理异常。以下是一个演示try函数的示例&#xff1a; #include <iostream> #include <stdexcept>double division(int x, int y) {if (y 0) {throw std::runtime_error("Divide by zero error");}return x / y; }in…

005-GeoGebra基础篇-GeoGebra的点

新手刚开始操作GeoGebra的时候一般都会恨之入骨&#xff0c;因为有些操作不进行学习确实有些难以凭自己发现。 目录 一、点的基本操作1. 通过工具界面添加点2. 关于点的选择&#xff08;对象选择通用方法&#xff09;&#xff08;1&#xff09;选择工具法&#xff08;2&#xf…

Vue3使用jsbarcode生成条形码,以及循环生成条形码

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;我是前端菜鸟的自我修养&#xff01;今天给大家分享Vue3使用jsbarcode生成条形码&#xff0c;以及循环生成条形码&#xff0c;介绍了JsBarcode插件的详细使用方法&#xff0c;并提供具体代码帮助大家深入理解&#xff0c;彻…

【Docker】集群容器监控和统计 CAdvisor+lnfluxDB+Granfana的基本用法

集群容器监控和统计组合&#xff1a;CAdvisorlnfluxDBGranfana介绍 CAdvisor&#xff1a;数据收集lnfluxDB&#xff1a;数据存储Granfana&#xff1a;数据展示 ‘三剑客’ 安装 通过使用compose容器编排&#xff0c;进行安装。特定目录下新建文件docker-compose.yml文件&am…

日志分析-windows系统日志分析

日志分析-windows系统日志分析 使用事件查看器分析Windows系统日志 cmd命令 eventvwr 筛选 清除日志、注销并重新登陆&#xff0c;查看日志情况 Windows7和Windowserver2008R2的主机日志保存在C:\Windows\System32\winevt\Logs文件夹下&#xff0c;Security.evtx即为W…

【OCPP】ocpp1.6协议第4.8章节Start Transaction的介绍及翻译

目录 4.8、开始交易Start Transaction-概述 Start Transaction StartTransaction.req 请求消息 StartTransaction.conf 确认消息 交易管理流程 小结 4.8、开始交易Start Transaction-应用场景 1. 公共充电站 场景要点: 2. 商业充电设施 场景要点: 3. 住宅充电桩 …

【51单片机】串口通信(发送与接收)

文章目录 前言串口通信简介串口通信的原理串口通信的作用串口编程的一些概念仿真图如何使用串口初始化串口串口模式波特率配置 发送与接收发送接收 示例代码 总结 前言 在嵌入式系统的开发中&#xff0c;串口通信是一种常见且重要的通信方式。它以其简单、稳定的特性在各种应用…

使用c++回旋打印二叉树的节点

设计一个算法来回旋打印二叉树的节点。这个算法的基本思想是使用层序遍历&#xff08;广度优先搜索&#xff09;来访问树的节点&#xff0c;但是在打印时交替改变方向。下面是用C实现的代码 #include <iostream> #include <queue> #include <vector> #inclu…

[小试牛刀-习题练]《计算机组成原理》之计算机系统概述【详解过程】

【计算机系统概述】 1、【冯诺伊曼结构】计算机中数据采用二进制编码表示&#xff0c;其主要原因是&#xff08;D&#xff09; I、二进制运算规则简单II、制造两个稳态的物理器件较为容易III、便于逻辑门电路实现算术运算 A.仅I、Ⅱ B.仅I、Ⅲ C.仅Ⅱ、Ⅲ D. I、Ⅱ、Ⅲ I…

基于 Spring Boot 的健康咨询系统

1 项目介绍 1.1 摘要 本项目旨在通过构建一个对用户更加友好的健康咨询平台&#xff0c;帮助用户方便、快捷地获取专业并且准确的健康咨询服务&#xff0c;同时为医疗机构提供一个高效易用的可以提供信息管理的服务平台。 项目采用了Spring Boot框架作为主要的开发平台。本系…

论文阅读_基于嵌入的Facebook搜索

英文名称&#xff1a;Embedding-based Retrieval in Facebook Search 中文名称&#xff1a;基于嵌入式检索的Facebook搜索 时间&#xff1a;Wed, 29 Jul 2020 (v2) 地址&#xff1a;https://arxiv.org/abs/2006.11632 作者&#xff1a;Jui-Ting Huang, Ashish Sharma, Shuying …

Postman设置请求间自动保存返回参数,方便后续请求调用,减少复制粘贴

postman中常常出现&#xff1a;有两个请求&#xff0c;一个请求首先获取验证码或者token&#xff0c;再由得到的验证码或token编写body发送另一个请求。如何设置两个请求间自动关联相关数据呢&#xff1f; 通过环境存储全局变量 现在有两个请求如下图&#xff0c;生成验证码是…

如何将Hive表的分区字段插入PG表对应的时间戳字段?

文章目录 1、背景描述2、场景分析 1、背景描述 数据仓库的建设通常是为业务和决策服务的。在数仓开发的应用层阶段&#xff0c;BI可以直接从主题层/业务层取数&#xff0c;而前端需要根据具体的作图需求通过后端查询数据库 作图的指标需要根据主题层/业务层做查询计算&#xf…

保姆教程教你如何使用数据集运行ORB-SLAM3

链接: 自学SLAM&#xff08;2&#xff09;—保姆教程教你如何使用自己的视频运行ORB-SLAM2 这篇文章是详细教怎么运行ORB-SLAM2的&#xff0c;那么下来我们就看看怎么运行ORB-SLAM3 理论上ORB-SLAM2的环境也是可以跑ORB-SLAM3的&#xff0c;因为我之前试过&#xff0c;编译成功…