C++项目实践学习笔记---DLL

linux守护进程

  • 守护进程或精灵进程(Daemon):以后台服务方式运行的进程,它们不占用终端(Shell),因此不会受终端输入或其他信号(如中断信号)的干扰
  • 守护进程有如下特点。
    (1)守护进程没有控制终端,不能直接和用户交互,不会接收终端输入或信号,也不能向终端输出信息。
    (2)其他进程都是在用户登录或者运行程序时创建,在运行结束或用户注销时终止,但守护进程不受用户登录、注销的影响,它只受开机、关机的影响。
  • 守护进程和后台进程的区别如下。
    (1)守护进程是后台进程,但后台进程不一定是守护进程。
    (2)守护进程运行时与终端无关,不能向终端输出消息,因此不会受终端影响,即使关闭终端或用户注销(退出操作系统登录状态),守护进程也会继续运行;
    后台进程并未脱离终端,后台进程可以向终端输出信息并可接收来自终端的信号(如中断信号),关闭终端会导致该终端中运行的后台进程退出,用户注销也会导致后台进程退出。
    (3)守护进程的所属会话、当前目录、文件描述符都是独立的;后台进程只是终端进行了一次fork()函数,让程序在后台执行,因此后台进程的当前目录、文件描述符等都依赖所在终端。
  • 如何让一个进程变成守护进程
    1)创建子进程,终止父进程
    fork()函数通过系统调用创建一个与原来进程几乎完全相同的进程,
    一个进程调用fork()函数后,系统先给新的进程分配资源(如存储数据和代码的空间),
    然后把原来进程的所有值都复制到新进程中,只有少数值与原进程的值不同,这相当于克隆了一个进程。
    新旧两个进程可以做完全相同的事,也可以做不同的事,这可以由初始参数决定.
    fork()函数只会把下一个要执行的代码以及之后的代码复制到新进程
    fork()函数可能有以下三种不同的返回值。
    在父进程中,调用fork()函数成功,并且新创建子进程的进程ID>0。此时输出的信息见标号③处。
    在子进程中,fork()函数返回0。此时输出的信息见标号④处。
    如果出现错误,则fork()函数返回一个负值。此时可以通过errno的值判断错误原因。
    通过fork()函数返回的值来判断当前进程是子进程还是父进程
    在这里插入图片描述
    2)在子进程中创建新会话
    setsid()函数用于创建一个新的会话,并将调用它的进程设置为该会话组的组长
    setsid()函数有三个作用:让进程脱离原会话、让进程脱离原进程组、让进程脱离原终端
    调用setsid()函数的进程不能是进程组组长,父进程不能调用setsid()函数,即使调用也会失败
    需要先调用fork()函数创建子进程,这样的话父进程仍是会话组长、进程组长,而子进程不是。
    当子进程调用完setsid()函数之后,子进程是新会话的会话组长,也是新的进程组组长,并且脱离了控制终端
    //创建守护进程(后台进程)的函数
    #include<unistd.h>
    pid_t setsid(void);
    在这里插入图片描述
    3)关闭文件描述符
    通过fork()函数方式创建的子进程会从父进程那里继承一些已经打开的文件句柄。子进程可能永远不会操作这些被打开的文件,但它们却会消耗系统资源,而且可能导致文件所在的文件系统(如U盘、光盘)无法卸载。为了避免这种情况,需要关闭文件描述符,见代码清单2-16中标号①处。当关闭文件描述符之后再调用printf()之类接口时可能导致异常,这是因为printf()接口默认对终端进行操作,而此时进程已经同终端脱离了。因此应该把标准输入stdin、标准输出stdout、标准错误输出stderr进行重定向,见标号②处。
    在这里插入图片描述
    4)改变工作目录
    通过fork()创建的子进程也会继承父进程的当前工作目录。如果进程运行过程中一直占用该目录,将导致当前目录所在的文件系统不能卸载,因此,应该把当前工作目录换成其他的路径,如“/”。
    chdir(“/”);//更改目录防止占用可卸载的文件系统
    5)重设文件创建掩码
    通过fork()方式创建的子进程会从父进程那里继承文件创建掩码。文件创建掩码指的是屏蔽掉文件创建时对应的访问权限位。文件的访问权限共有9种,分别是用户读、用户写、用户执行、组读、组写、组执行、其他读、其他写、其他执行。可以通过umask()设置文件创建掩码,其实这个函数的作用就是为当前进程设置创建文件或者目录的最大可操作权限。比如,umask(0)的含义是0取反再与创建文件时的权限相与。如果用mode代表文件创建权限,那么umask(0)的含义是(~0)&mode,也就是八进制的777&mode。这样的话,在此之后的代码在创建文件或目录时就可以给出最大的权限,避免了创建目录或文件时权限的不确定性。
    umask(0);// 重设文件创建掩码

在Windows系统中以后台服务方式运行程序

  • 1.注册/注销服务
    引入Advapi32.lib库,
    在这里插入图片描述

2.启动服务
start_service()的实现如下。该接口通过调用“::StartServiceCtrlDispatcher()”实现了服务的启动。
在这里插入图片描述
3.在进程中增加对注册、注销、启动服务接口的调用代码
完成服务的注册、注销、启动接口后,就可以在应用进程中调用这些接口了。

  • 将DLL中供EXE调用的类或接口称作引出类、引出接口。
    (1)将DLL中引出类(export)的头文件移动到公共include目录。
    (2)在DLL的pro项目文件中定义宏。
    (3)编写DLL引出宏的头文件。
    (4)在DLL引出类的头文件中使用引出宏。
    (5)在EXE项目中添加对DLL的引用。
    (6)在EXE中调用DLL的接口。
    (7)使用命名空间解决重名问题。
    (8)使用命名空间的注意事项。

在这里插入图片描述
在Windows中,WINAPI被定义为_ _stdcall

  • 动态加载的DLL和静态链接的DLL有什么区别:
    (1)构建过程中对DLL的lib文件的依赖不同。如果使用静态链接的DLL,在构建EXE项目时需要用到DLL的lib文件,以便链接DLL中的符号,如引出类、引出接口;如果使用动态加载的DLL,在构建EXE项目时不需要DLL的lib文件。
    (2)在运行过程中,对DLL的依赖时间不同。如果使用静态链接的DLL,EXE整个运行过程中都要依赖DLL库文件(如a.dll);如果使用动态加载的DLL,EXE只有在加载该DLL后才依赖DLL库文件,而在卸载DLL后就不再依赖DLL库文件了,这时即使删除该DLL库文件也不影响EXE的正常运行。

  • 开发动态加载的DLL分为两步,第一步是开发可动态加载的DLL,第二步是动态加载DLL

  • extern "C"是让C++代码能够调用C代码写的接口而采用的一种语法形式

  • Windows动态加载DLL步骤:

  • 加载DLL: HMODULE WINAPI LoadLibrary(In LPCTSTR lpFileName);
    _In_表示后面的参数是输入参数,也就是在接口内部只会引用传入的参数,而不会修改它。
    参数lpFileName表示要加载的DLL名称,如果DLL所在路径已经配置到PATH环境变量,就可以不写全路径而只写DLL文件名
    HMODULE是返回值类型,它是一个句柄,用来操作打开的DLL
    HMODULE hDll = LoadLibrary(“my_dll.dll”);

  • 查找DLL中的接口:
    WINBASEAPI FARPROC WINAPI GetProcAddress(In HMODULE hModule, In LPCSTR
    lpProcName);
    WINBASEAPI宏用来表明后面是一个引出接口。
    FARPROC表示该接口的返回值类型是一个函数地址,也就是DLL中接口的地址。
    hModule是指向DLL的句柄,hModule可以取LoadLibrary()的返回值。
    lpProcName表示要查找的接口名
    void *pFuncAddress = GetProcAddress(hDll, “function_test”);

  • 调用DLL中的接口、

  • 在这里插入图片描述

  • 卸载DLL
    WINBASEAPI BOOL WINAPI FreeLibrary(In_ HMODULE hLibModule)
    hLibModule表示DLL的句柄,该句柄可以由LoadLibrary()得到。
    FreeLibrary()返回BOOL类型的值,用来表示卸载成功与否
    FreeLibrary(hDll);

  • 在Linux中动态加载DLL并调用DLL中的接口步骤

  • (1)如果要调用DLL中的接口,首先需要加载DLL。在Linux中加载DLL的接口为dlopen(),调用该接口需要包含头文件“#include <dlfcn.h>”, - void* dlopen(const char pathName, int mode);
    其中pathName表示要加载的DLL名称,如果DLL所在路径已经配置到PATH环境变量,就可以不写全路径而只写DLL文件名。
    mode 表示加载模式,在本案例中取值RTLD_LAZY,表示等需要时再解析DLL中的符号(即函数)。
    该函数返回值类型为void
    。调用dlopen()的示例代码如下。
    void *hDll = dlopen(“my_dll.so.1”, RTLD_LAZY);
    该例子表示加载的DLL为"my_dll.so.1"。需要注意的是Linux中的DLL文件一般会有多个软链接(类似Windows中的快捷方式),在使用前需要确认该文件名与磁盘上DLL的实际文件名是否一致,如果不一致将导致加载失败

  • (2)在Linux系统中加载DLL后,可以用dlsym()查找DLL中的接口, void* dlsym(void *handle, const char symbol);
    void
    指向返回的函数地址。
    handle是指向DLL的指针,可以取dlopen()的返回值。
    symbol表示要查找的接口名。
    调用dlsym()的示例代码如下。
    void *pFuncAddress = dlsym(hDll, “function_test”);
    该示例表示在hDll所指向的DLL中查找函数function_test并将找到的函数地址保存到pFuncAddress中。

  • (3)找到DLL中的接口后,就可以调用它了。

  • (4)完成接口调用后,如果不需要再调用该DLL中的接口,可以在适当的时机卸载DLL。但是,如果仍然需要调用其中的接口,就不能卸载DLL,否则将导致接口调用异常。在Linux中卸载DLL的接口为dlclose(), int dlclose (void *handle);
    其中handle表示DLL的句柄,该句柄可以由dlopen()得到。只有当DLL的使用计数为0时,DLL才会真正被系统卸载。 dlclose(hDll);
    注意:如果要使用dlopen()、dlclose()等接口,需要在项目的pro中添加对Linux库dl的引用,否则会导致编译错误“undefined reference to symbol ‘dlclose@@GLIBC_2.2.5’”

将动态加载DLL的功能封装到自定义类

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

如何做好新闻软文宣发媒体资源筛选?

传媒如春雨&#xff0c;润物细无声&#xff0c;大家好&#xff0c;我是51媒体网胡老师。 媒体宣传加速季&#xff0c;100万补贴享不停&#xff0c;一手媒体资源&#xff0c;全国100城线下落地执行。详情请联系胡老师。 新闻软文宣发是指企业通过创造或利用新闻事件&#xff0c…

【JAVA多线程】JMM,成体系聊一下JAVA线程安全问题

目录 1.什么是JMM 2.现代计算机架构 3.线程安全理论 3.1.造成线程安全问题的原因 3.1.1.内存不可见 3.1.2.重排序 3.2.解决思路 3.2.1.as-if-serial 3.2.2.happen-before 4.线程安全实现 4.1.Synchronized 4.2.volatile 1.什么是JMM JMM&#xff0c;全称为Java Me…

胶质瘤的发病原因及诊断方式有哪些?

胶质瘤&#xff0c;这个听起来有些陌生的名词&#xff0c;实际上是一种起源于神经胶质细胞的常见脑肿瘤。它的发病原因复杂&#xff0c;涉及遗传、环境、年龄及感染等多种因素。 首先&#xff0c;遗传因素在胶质瘤的发病中占据一席之地。某些遗传性疾病&#xff0c;如结节性硬化…

【代码阅读】SSC:Semantic Scan Context for Large-Scale Place Recognition

一、主函数 官方开源的代码提供了四个主函数&#xff0c;其中eval_pair.cpp和eval_top1.cpp是一组&#xff0c;分别用于计算两帧的相似度分数以及一帧点云在所有的51帧点云中相似度最高的25帧的相似度分数。eval_seq.cpp是在eval_top1.cpp的基础上&#xff0c;给了一堆序列&am…

【Java Web】会话管理

目录 一、为什么需要会话管理&#xff1f; 二、会话管理机制 三、Cookie概述 四、HttpSession概述 4.1 HttpSession时效性 一、为什么需要会话管理&#xff1f; HTTP协议在设计之初就是无状态的&#xff0c;所谓无状态就是在浏览器和服务器之间的通信过程中&#xff0c;服务器并…

简过网:上万元的学费,考公到底要不要报个培训班?

考公报不报班一直是很多朋友比较纠结一件事&#xff0c;报班了学费太贵&#xff0c;不报班又怕考不上&#xff0c;如果你也有这种困扰&#xff0c;那么&#xff0c;不妨看看这篇文章&#xff01; 首先&#xff0c;对于报班VS自学这个问题&#xff0c;小编的建议是&#xff1a;…

LICEcap-开源GIF 屏幕录制工具

LICEcap-开源GIF 屏幕录制工具 开源GIF 屏幕录制工具 下载可以访问&#xff1a;https://www.cockos.com/licecap/ 点击Record&#xff0c;开始录制 点击Stop&#xff0c;停止录制 点击Record&#xff0c;进入该页面 display in animation&#xff08;在动画中显示&#xff09; …

240627_昇思学习打卡-Day9-ResNet50图像分类

240627_昇思学习打卡-Day9-ResNet50图像分类 文章目录 240627_昇思学习打卡-Day9-ResNet50图像分类前言残差网络Residual Block代码实现Bottleneck Block代码实现 BN层&#xff08;Batch Normalization&#xff09;构建ResNet50网络数据集准备与加载模型训练与评估可视化模型预…

高德.js2.0绘制点聚合,并点击点出现自定义样式弹窗

我这里依旧使用AMapLoader插件 代码如下 // 初始化高德地图initMap() {AMapLoader.load({key: "fb35c92d4019cfafeca876fd5514bb47", //key值是key值 和安全密钥不同version: "2.0", // 指定要加载的 JSAPI 的版本&#xff0c;缺省时默认为 1.4.15plugins…

免费恢复微信好友的聊天记录(已删除的好友不能恢复)

非常简单,适用于未删除的微信好友的聊天记录恢复,支持导出 1、下载楼月微信聊天记录导出恢复助手 - 导出手机微信聊天记录 2、官方原文教程链接&#xff1a;官方原文教程链接https://www.louyue.com/weixin.htm

华为升腾显卡选型备忘

目录 1. 开发套件 2. 加速模块 3. 加速卡 4. 训练卡 官方地址&#xff1a;https://www.hiascend.com/ 备注&#xff1a; &#xff08;1&#xff09;V后缀的都是Video视频解析卡&#xff0c;本质是推理卡&#xff1b; &#xff08;2&#xff09;I后缀的都是推理卡&#…

如何通过小猪APP分发轻松实现应用内测分发

搞应用开发的朋友们&#xff0c;都知道内测分发这个环节有多重要。没有内测&#xff0c;一款应用基本上是不可能上线的。毕竟&#xff0c;谁也不想自己的产品在上线的那一刻就被用户吐槽得体无完肤。内测分发的好坏&#xff0c;直接影响到应用的质量和用户的第一印象。如何才能…

postGreSQL关系数据库介绍

什么是postGreSQL关系数据库&#xff1f; PostgreSQL 是一个强大的、开源的对象关系型数据库管理系统&#xff08;ORDBMS&#xff09;。它基于POSTQUEL查询语言的继承&#xff0c;提供了对SQL标准的广泛支持&#xff0c;并扩展了许多高级功能&#xff0c;如事务处理、多版本并…

使用Python实现深度学习模型通常涉及以下几个步骤

学习总结 1、掌握 JAVA入门到进阶知识(持续写作中……&#xff09; 2、学会Oracle数据库入门到入土用法(创作中……&#xff09; 3、手把手教你开发炫酷的vbs脚本制作(完善中……&#xff09; 4、牛逼哄哄的 IDEA编程利器技巧(编写中……&#xff09; 5、面经吐血整理的 面试技…

光电液位传感器工作时容易受哪些因素影响?

光电式水位传感器的检测液位时是必须要接触液体才能进行检测的。当液体覆盖光电式水位传感器的探头时&#xff0c;传感器内的发光二极管发射出去的光线会折射在液体中&#xff0c;而光敏接收器只能接收到少量光电或者接收不到光线。反之正常接收光线则是无水状态。 光电式水位…

想买骨传导耳机怕踩雷?全方位的选购攻略分享给你!

作为一个爱好运动的人来说&#xff0c;现在天气越来越暖和了&#xff0c;很多人选择外出徒步、越野或者骑行。在运动过程中都会佩戴一些入耳式耳机&#xff0c;但是运动一段时间发现入耳式耳机带久了耳朵会很不舒服&#xff0c;而且出汗了的话对于一些不防水的入耳式耳机的话&a…

swiper轮播 loop:true失效解决

数据是写死的时候&#xff0c;能够loop:true是有效的;数据是动态获取的loop:true就会失效。 方法一&#xff1a;在接收到数据后&#xff0c;使用 setTimeout(() > {this.getSwiper(); //生成swiper方法}, 0); 下面是我项目具体使用的参考例子&#xff1a; 方法二&#xff…

详细解释Spring事务的传播机制

详细解释Spring事务的传播机制 Spring框架中&#xff0c;事务传播机制是指在一个事务方法调用另一个事务方法时&#xff0c;Spring如何管理这些方法之间的事务边界。Spring提供了七种事务传播行为&#xff0c;以满足不同的业务需求。下面将详细解释每种传播行为及其适用场景&a…

IDEA 安装与激活详细教程最新(附最新激活码)2099年亲测有效!

我们先从 IDEA 官网下载 IDEA 2024.1 版本的安装包&#xff0c;下载链接如下&#xff1a; https://www.jetbrains.com/idea/download/ 点击下载(下载Ultimate版)&#xff0c;静心等待其下载完毕即可。 激活方式&#xff1a; 正版专属激活码领取

vcruntime140_1.dll是什么东东?vcruntime140_1.dll缺失的8个解决方法

当电脑出现找不到vcruntime140_1.dll,或vcruntime140_1.dll丢失无法打开软件怎么办&#xff1f;小编今天在本文详细为大家介绍解决方法与介绍vcruntime140_1.dll究竟是什么等vcruntime140_1.dll的问题。 一、vcruntime140_1.dll文件是什么 文件概述定义与功能 vcruntime140_…