你真的懂动态库吗?一文详解动态库的方方面

创建动态库

1.【新建】-》【项目】-》【动态链接库】
在这里插入图片描述
新建的动态库结构如下:
在这里插入图片描述
新建项目:MathLibrary.h

// MathLibrary.h - Contains declarations of math functions
#pragma once

#ifdef MATHLIBRARY_EXPORTS
#define MATHLIBRARY_API __declspec(dllexport)
#else
#define MATHLIBRARY_API __declspec(dllimport)
#endif

// The Fibonacci recurrence relation describes a sequence F
// where F(n) is { n = 0, a
//               { n = 1, b
//               { n > 1, F(n-2) + F(n-1)
// for some initial integral values a and b.
// If the sequence is initialized F(0) = 1, F(1) = 1,
// then this relation produces the well-known Fibonacci
// sequence: 1, 1, 2, 3, 5, 8, 13, 21, 34, ...

// Initialize a Fibonacci relation sequence
// such that F(0) = a, F(1) = b.
// This function must be called before any other function.
extern "C" MATHLIBRARY_API void fibonacci_init(
	const unsigned long long a, const unsigned long long b);

// Produce the next value in the sequence.
// Returns true on success and updates current value and index;
// false on overflow, leaves current value and index unchanged.
extern "C" MATHLIBRARY_API bool fibonacci_next();

// Get the current value in the sequence.
extern "C" MATHLIBRARY_API unsigned long long fibonacci_current();

// Get the position of the current value in the sequence.
extern "C" MATHLIBRARY_API unsigned fibonacci_index();

注意头文件中的预定义宏:

#ifdef MATHLIBRARY_EXPORTS
#define MATHLIBRARY_API __declspec(dllexport)
#else
#define MATHLIBRARY_API __declspec(dllimport)
#endif

在动态库设置预定义宏,
在这里插入图片描述
添加项目,MathLibrary.cpp

// MathLibrary.cpp : Defines the exported functions for the DLL.
#include "pch.h" // use stdafx.h in Visual Studio 2017 and earlier
#include <utility>
#include <limits.h>
#include "MathLibrary.h"

// DLL internal state variables:
static unsigned long long previous_;  // Previous value, if any
static unsigned long long current_;   // Current sequence value
static unsigned index_;               // Current seq. position

// Initialize a Fibonacci relation sequence
// such that F(0) = a, F(1) = b.
// This function must be called before any other function.
void fibonacci_init(
	const unsigned long long a,
	const unsigned long long b)
{
	index_ = 0;
	current_ = a;
	previous_ = b; // see special case when initialized
}

// Produce the next value in the sequence.
// Returns true on success, false on overflow.
bool fibonacci_next()
{
	// check to see if we'd overflow result or position
	if ((ULLONG_MAX - previous_ < current_) ||
		(UINT_MAX == index_))
	{
		return false;
	}

	// Special case when index == 0, just return b value
	if (index_ > 0)
	{
		// otherwise, calculate next sequence value
		previous_ += current_;
	}
	std::swap(current_, previous_);
	++index_;
	return true;
}

// Get the current value in the sequence.
unsigned long long fibonacci_current()
{
	return current_;
}

// Get the current index position in the sequence.
unsigned fibonacci_index()
{
	return index_;
}

相关文献:
演练:创建和使用自己的动态链接库 (C++)

创建静态库

具体参见《演练:创建并使用静态库》,这里不再详述。

动态库与静态库的区别

名称不同:
静态库:.lib
动态库:
.dll

链接方式不同:
静态库采用静态链接方式,在程序链接阶段,静态库与汇编生成的目标文件一起打包到程序可执行文件*.exe中。
静态库对函数库的链接是在编译阶段完成的,运行时与函数库没有关系了。
所有的目标文件和函数库都会链接到程序可执行文件中,比较浪费空间和资源。

动态库在编译时并不会被链接到目标代码中,而是在程序运行的时候才被载入。
动态链接方式==》动态链接又包括显示链接和隐士链接。

多个程序引用
当一个静态库A被多个程序使用时,每个程序都会有A的一个拷贝,比较浪费空间。
不同程序使用相同的动态库,动态库在内存中只有一份实例,可以实现进程之间资源共享。==》动态库也叫做共享库。

程序更新:
如果静态库更新了,所有使用它的程序都需要重新编译。

注意:
静态库的lib和动态库的lib不是一个概念,
静态库的lib叫做静态库,动态库里面的lib叫做导入库。
静态库lib包含实际执行代码和符号表等;导入库,实际执行代码在动态库中,导入库只包含了地址符号表等。

相关文献:
C++静态库与动态库

动态链接与静态链接的区别

相关文献
深入浅出静态链接和动态链接

动态库的加载过程

dll的创建以及应用程序隐式链接到dll的过程

  1. 头文件中,包含导出函数的原型、结构和符号的说明
  2. c/c++源文件,其中包含待导出函数的实现和变量
  3. 编译器为每个源文件生成.obj文件
  4. 链接器将为每个obj模块合并,生成dll
  5. 如果至少导出一个函数或变量,链接器同时生成lib文件
    构建exe
  6. 头文件,包含导出函数的原型、结构和符号的声明
  7. 源文件,包含待导出函数的实现和变量
  8. 编译器为每个源文件生成obj文件
  9. 链接器将每个obj模块合并,并使用lib文件来解析导入的函数/变量的引用,从而生成exe。(它包含一个导入表,其中列出了必需的dll和导入的符号)
    运行应用程序
    加载程序创建地址空间
    加载程序将必需的dll载入到地址空间
    进程的主线程开始执行,应用程序开始执行

dll的创建以及应用程序显示链接到dll的过程

  • 头文件中,包含导出函数的原型、结构和符号的说明
  • c/c++源文件,其中包含待导出函数的实现和变量
  • 编译器为每个源文件生成.obj文件
  • 链接器将为每个obj模块合并,生成dll
  • 如果至少导出一个函数或变量,链接器同时生成lib文件(显示链接没有用到这个lib文件)
    构建exe
  • 头文件,包含导出函数的原型、结构和符号的声明
  • 源文件,包含待导出函数的实现和变量
  • 编译器为每个源文件生成obj文件
  • 链接器将每个obj模块合并,从而生成exe。(由于没有直接引用dll的导入符号,因此这里不需要它的lib文件,生成的exe不包含导入表)
    运行应用程序
  • 加载程序创建地址空间 进程的主线程开始执行,应用程序开始执行
  • 线程调用loadLiberay来将dll载入到进程的地址空间中。
  • 各个线程可以调用GetProAddress来简接地引用dll导出的符号。

动态库的二进制兼容性

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Python 中的线程睡眠可以通过 `time.sleep()` 函数来实现,该函数会让当前线程暂停指定的时间,单位为秒。例如,以下代码会让当前线程睡眠 1 秒钟: ```python import time print("start") time.sleep(1) print("end") ``` 输出: ``` start (end 1 秒钟后输出) ``` 需要注意的是,线程睡眠会让当前线程阻塞,即当前线程会暂停执行,等待指定的时间后再继续执行。如果在主线程中使用线程睡眠,会导致整个程序的执行被暂停。 另外,需要注意的是 Python 中的线程与操作系统的线程并不是一一对应的关系,Python 解释器会使用一个全局锁来保证同一时刻只有一个线程在执行 Python 代码。因此,如果在 Python 中使用多线程,可能会出现线程间的竞争和阻塞,需要使用适当的同步机制(如锁、信号量等)来解决。 至于后台线程,它是一种特殊的线程,在程序退出时会自动结束,不需要等待其执行完成。可以通过设置线程对象的 `daemon` 属性来创建后台线程。例如,以下代码创建了一个后台线程: ```python import threading import time def count(): for i in range(5): print(i) time.sleep(1) t = threading.Thread(target=count) t.daemon = True t.start() print("main thread exit") ``` 输出: ``` 0 main thread exit 1 2 3 4 ``` 注意,当主线程退出时,后台线程也会随之结束,即使后台线程没有执行完毕。因此,需要确保后台线程的执行时间不会超过主线程的生命周期。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

haimianjie2012

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值