目录
科学名词 命令
进程地址空间的共享区
在进程地址空间中,共享区是指多个进程之间共享的内存区域。共享内存是一种进程间通信和数据同步的技术,它允许不同进程之间在同一块内存区域中读取和写入数据。共享内存通常用于实现多线程或多进程之间的数据交换,以提高程序的执行效率和响应速度。
在进程地址空间中实现共享内存的方法通常是在操作系统中为多个进程分配一块共享内存区域,并允许这些进程访问该区域。共享内存的实现需要解决进程间的同步和互斥问题,以避免多个进程同时访问共享内存区域时发生数据竞争或冲突。
拓展:
在Linux中,进程地址空间的共享区通常是通过共享内存机制来实现的。共享内存允许多个进程共享同一块内存区域,以便它们可以直接访问共享的数据,从而实现高效的进程间通信。
Linux提供了多种方式来创建和管理共享内存区域,其中最常见的方法是使用System V共享内存和Posix共享内存。
System V共享内存:
-
创建共享内存区域:使用shmget()系统调用来创建一个共享内存区域。该调用接受三个参数,分别是共享内存的键值、大小和标志。成功创建后,shmget()会返回一个唯一的标识符(shmid)。
-
连接共享内存:使用shmat()系统调用将共享内存区域连接到进程的虚拟地址空间。shmat()有两个参数,一个是shmid,另一个是指定连接方式的标志。成功连接后,shmat()会返回共享内存的起始地址。
-
使用共享内存:进程可以直接通过指针访问共享内存区域,就像访问本地内存一样。共享内存的访问并没有加任何额外的同步机制,因此进程需要自行实现进程间数据同步和互斥。
-
分离共享内存:进程使用shmdt()系统调用将共享内存区域从自己的地址空间中分离。成功分离后,该进程将不再能访问共享内存区域。
-
删除共享内存:使用shmctl()系统调用可以删除共享内存区域。该调用接受三个参数,分别为shmid,命令(IPC_RMID)和指向共享内存信息结构的指针。
Posix共享内存:
与System V共享内存不同,Posix共享内存采用了更加灵活的接口,更加符合POSIX标准,并且提供了更多的功能和操作。
-
创建共享内存区域:使用shm_open()函数创建一个共享内存对象。该函数接受两个参数,一个是共享内存的名称(类似文件名),另一个是标志。
-
设置共享内存大小:使用ftruncate()函数设置共享内存的大小,即划定共享内存区域的大小。
-
连接共享内存:使用mmap()函数将共享内存映射到进程的地址空间中。mmap()需要指定共享内存对象的文件描述符、映射的长度、映射的权限和映射的标志。
-
使用共享内存:进程可以直接通过指针访问共享内存区域,进行数据读写等操作。
-
分离共享内存:使用munmap()函数将共享内存区域从进程地址空间中解除映射。
-
删除共享内存:使用shm_unlink()函数可以删除共享内存对象。
总结:
Linux中的进程地址空间的共享区利用共享内存机制,允许多个进程共享同一块内存区域,从而实现高效的进程间通信。在使用共享内存时,需要注意进程之间的同步和互斥,以避免数据竞争和冲突。
动静态库
动态库(Dynamic Link Library)和静态库(Static Library)是两种常见的软件库,它们在程序编译和运行时起着不同的作用。
动态库(Dynamic Link Library)
动态库在程序运行时被加载,它们不是直接编译到程序的二进制代码中,而是存在于程序的执行文件中的一份引用。操作系统负责在程序运行时将这些动态库加载到内存中。
动态库的优点包括:
-
可共享:同一个动态库可以在多个程序之间共享,从而减少了内存占用和磁盘空间的需求。
-
易于更新:更新动态库不需要重新编译或安装程序,只需替换旧的库文件即可。
-
灵活性:动态库允许程序在运行时动态地加载和卸载,增加了程序的灵活性和可扩展性。
动态库的缺点包括:
-
初始加载时间:动态库在程序启动时需要加载,可能会增加程序的启动时间。
-
性能影响:每次程序运行时,操作系统都需要花费时间来加载动态库,这可能会导致微小的性能开销。
静态库(Static Library)
静态库在程序编译时被整合到程序的二进制中。这意味着,一旦程序编译完成,静态库的代码就会包含在可执行文件中。
静态库的优点包括:
-
快速加载:由于库的代码已经包含在可执行文件中,因此程序启动时不需要额外的时间来加载库。
-
性能优化:程序可以直接访问静态库的代码,无需操作系统介入,这可能会提高程序的运行效率。
静态库的缺点包括:
-
不可共享:每个程序都有其自己的静态库副本,这会增加磁盘空间的使用,并且不利于资源的共享。
-
更新困难:更新静态库通常需要重新编译和安装程序。
一个经常需要更新的用户界面库可能会更适合作为动态库使用,而一个性能关键的库可能会作为静态库提供。
归档文件
归档文件(Archive file)是指将多个文件或目录组合成一个单一的文件的一种文件格式。归档文件通常用于将相关文件捆绑在一起以进行便捷的传输、存储或归档。在Linux系统中,常见的归档文件格式是tar和zip。
Tar归档文件(.tar):
-
Tar(Tape Archive)是Linux中常用的归档工具。它将多个文件和目录组合成一个单一的文件,尽可能地保持目录结构和文件属性。
-
tar命令用于创建、提取和展示.tar文件。例如,使用以下命令创建.tar文件:
tar -cvf archive.tar file1.txt file2.txt dir1/
Zip归档文件(.zip):
-
Zip是一种非常流行的归档文件格式,在Linux和Windows等多个操作系统上广泛使用。它可以压缩和归档多个文件和目录,并提供压缩和加密功能。
-
zip命令用于创建、提取和展示.zip文件。例如,使用以下命令创建.zip文件:
zip archive.zip file1.txt file2.txt dir1/
在使用归档文件时,可以轻松地将多个文件或目录打包为一个单一文件,并进行传输、备份或共享。通过提取归档文件,你可以还原被打包的文件和目录到原始的目录结构中。
值得注意的是,归档文件通常只用于组合文件和目录,并不会改变它们的内容。如果需要进行文件的压缩,可以在归档文件创建后,再对归档文件进行压缩,例如使用gzip或bzip2等压缩程序。
ar
ar
命令是 Linux 中用于管理归档文件 (archive files) 的常用工具。可以创建、修改、删除和提取归档文件中的成员文件,还可以创建符号表和索引,以及查看归档文件的详细信息。
主要参数及其介绍:
-
-c
:创建新的空归档文件。 -
-d
:删除归档文件中的成员文件。 -
-r
:将文件添加到归档文件中。 -
-m
:修改归档文件中成员文件的位置。 -
-t
:列出归档文件中包含的文件。 -
-x
:从归档文件中提取成员文件。 -
-p
:查看归档文件中指定成员文件的内容。 -
-q
:将问号字符附加到归档文件的末尾。 -
-o
:将归档文件保存到指定的文件中。 -
-f
:指定要处理的文件名。 -
-F
:从标准输入中读取文件名。 -
-j
:为 JAR 文件创建索引。 -
-J
:显示 JAR 文件的索引。 -
-M
:显示归档文件的成员文件信息。 -
-S
:创建符号表。 -
-s
:删除符号表。 -
-S
:删除符号表。 -
-x
:从归档文件中提取成员文件。 -
-l
:查看符号表。 -
-L
:查看符号表中的所有符号。 -
-n
:显示归档文件中每个成员文件的文件名和大小。 -
-N
:显示归档文件中每个成员文件的文件名、大小和修改日期。 -
-v
:显示详细信息。 -
-V
:显示版本信息。 -
示例:
-
创建一个新的空归档文件:
ar -c new_archive.ar
-
将文件添加到归档文件中:
ar -rv old_archive.ar new_file.txt
-
修改归档文件中成员文件的位置:
ar -mv old_archive.ar new_position.txt
-
列出归档文件中包含的文件:
ar -t old_archive.ar
-
从归档文件中提取成员文件:
ar -x old_archive.ar member_file.txt
-
查看归档文件中指定成员文件的内容:
ar -p old_archive.ar member_file.txt
-
为 JAR 文件创建索引:
ar -j old_archive.jar
-
显示 JAR 文件的索引:
ar -J old_archive.jar
ldd
在Linux中,ldd
命令用于显示可执行文件或共享库文件所依赖的动态链接库(shared libraries)信息。它会列出程序运行所需的共享库及其路径。
-
-d
:显示库的调试信息,包括所需库的版本、路径等。 -
-r
:递归显示依赖关系,即显示被依赖的库。 -
-u
:显示未使用的直接依赖库。 -
-v
:显示更详细的信息, 包括使用的共享库版本号和加载地址。
使用示例:
ldd /path/to/program
上述命令将显示程序所依赖的动态链接库列表和路径。
请注意,ldd
命令只能用于可执行文件或共享库文件,而不能用于静态库文件(如.a
文件)。
编写自己的静态库
文件
-
创建头文件(Header Files):
mylibrary.h
#ifndef MYLIBRARY_H #define MYLIBRARY_H void sayHello(); int add(int a, int b); class MyClass { public: void printName(); }; #endif
-
实现代码(Implementation Files):
mylibrary.cpp
#include "mylibrary.h" #include <iostream> void sayHello() { std::cout << "Hello from my library!" << std::endl; } int add(int a, int b) { return a + b; } void MyClass::printName() { std::cout << "This is MyClass." << std::endl; }
-
构建静态库:
编写Makefile文件
lib=libmylibrary.a $(lib):mylibrary.o ar -rc $@ $^ mylibrary.o:mylibrary.cpp g++ -c $^ .PHONY:clean clean: rm -rf *.o *.a lib .PHONY:output output: mkdir -p lib/include mkdir -p lib/mylibrarylib cp *.h lib/include cp *.a lib/mylibrarylib
首先,定义了两个变量:
-
lib
:这个变量的值是libmylibrary.a
,它表示要编译的静态库的名称。 -
$(lib)
:这个变量引用lib
变量的值,它将在后面的命令中使用。
然后,定义了一个规则来编译 mylibrary.o
文件:
-
mylibrary.o
:这是要编译的目标文件。 -
mylibrary.cpp
:这是要编译的源文件。 -
g++ -c $^
:这是编译命令,它将mylibrary.cpp
文件编译为mylibrary.o
文件。
接下来,定义了一个规则来创建静态库:
-
libmylibrary.a
:这是要创建的静态库文件。 -
$^
:这是要链接的 object 文件列表,它将在后面使用。 -
ar -rc $@ $^
:这是链接命令,它将mylibrary.o
文件链接为libmylibrary.a
文件。
最后,定义了两个规则来创建目录和复制文件:
-
lib/include
:这是要创建的目录,用于存放头文件。 -
lib/mylibrarylib
:这是要创建的目录,用于存放静态库文件。 -
cp *.h lib/include
:这是复制,它将*.h
文件复制到lib/include
目录中。 -
cp *.a lib/mylibrarylib
:这是复制命令,它将*.a
文件复制到lib/mylibrarylib
目录中。
这个 Makefile 示例中,使用 ar
命令来链接静态库文件。在链接过程中,使用了 -rc
参数,它将 libmylibrary.a
文件创建在当前目录下。
此外,这个 Makefile 示例中还定义了 clean
目标来删除所有 object 文件和静态库文件这有助于在开发过程中保持目录的整洁。
-
使用静态库:
main.cpp
#include"lib/include/mylibrary.h" #include<iostream> int main() { sayHello(); std::cout<< "5+50 = "<<add(5,50)<<std::endl; MyClass a; a.printName(); return 0; }
-
使用该静态库的项目需要告诉编译器及链接器使用该静态库。例如,如果你正在使用 GCC 编译器,可以在编译命令中添加
-I
指定头文件所在的目录,-L
标志指定静态库的路径,-l
标志指定静态库的名称
-
输出:
g++ m