Linux
文章平均质量分 61
Linux基本知识
一只老风铃
欣于所遇,暂得于己,快然自足。
展开
-
linux虚拟内存④:段与缺页
Linux虚拟内存系统Linux将进程的地址空间,将虚拟内存区域组成一些区域(段)的集合。一个区域就是已分配的虚拟内存连续片(chunk),这些段通过某种方式相互链接。一个进程的地址空间由下而上由多个不同类型的连续区域(段)组合而成:代码段、初始化数据段、未初始化数据段、运行时堆区域、共享库的映射区域、运行时栈区域、内核代码和数据段(多个进程通过虚拟内存方式共享)、内核为每个进程维护的元数据(页表、task_struct、mm结构)它们在虚拟地址空间中内部连续,中间则存在空隙,内核通过链表(原创 2021-03-18 10:48:00 · 375 阅读 · 0 评论 -
信号与不可重入
信号信号是软件中断。提供了一种处理异步事件的方法。例如当用户在终端输入中断键(ctrl+c),会向前台进程发送一个中止信号SIGINT,以此来中止一个进程。信号通常以SIG3个字符开头作为命名,例如SIGABRT是夭折信号;当进程调用abort函数时发出这种信号。SIGALARM是闹钟信号,由alarm函数设定的定时器超时后将产生这种信号。几种常见的信号类型:①当用户在终端输入某些键时,引起终端产生相应的信号。例如按下DELETE键或者Ctrl+C键将产生中断信号SIGINT。该信号用于停止一个原创 2020-12-05 00:37:17 · 352 阅读 · 0 评论 -
Linux进程执行环境
进程环境进程的环境,主要是描述是对程序执行时,main函数如何被调用;命令行参数以及环境变量如何传递给程序;进程的存储空间布局形式;以及进程终止方式;进程的资源限制等问题。一个典型的C程序总是从main开始执行 int main(argc,char* argv[]) 内核执行C程序时,其通过父进程采取exec函数,在调用main之前先调用一个启动例程。启动例程将命令行参数和环境变量从内核中获取,传递给进程。一个典型的C程序启动与终止:可以看到,总是从一个C启动例程开始,由它启动main函数,而原创 2020-11-14 02:49:34 · 399 阅读 · 0 评论 -
存储器层次②:局部性与高速缓存
局部性一个计算机程序常常具备良好的局部性。其含义是程序在未来总是倾向于访问那些最近使用过的数据周围附近的数据,或者是引用那个最近使用的数据本身。这就是局部性原理。局部性通常包含两种形式:①:时间局部性:一个被引用的内存位置在不久的将来很可能继续被访问②:空间局部性:一个内存位置被引用,其周围的附近位置很可能不久被访问。具备良好的局部性特性的程序通常有更好的性能。原因在于计算机系统中采取缓存保存那些最近使用的数据,那么在下一次访问到该数据时将大大缩短时间。另外,一些系统也采取预加载的技术,一次将原创 2020-11-13 21:44:39 · 491 阅读 · 0 评论 -
存储器层次①:内存访问
存储器层次存储器系统是一个具有不同的容量、成本、和访问时间的存储设备的层次结构。CPU寄存器作为最块的CPU访问设备,进一步是容量较小的高速缓存,具体包含L1 L2 L3级别的缓存。主内存通常作为磁盘上虚拟内存的缓存。而磁盘从某种角度上看又是其它网络数据的本地缓存。通常而言CPU寄存器在0个时钟周期内就可以访问到,而如果数据位于高速缓存中,则需要几十个时钟周期,若数据位于内存中,则需要上百个周期。因此,如何设计程序使得它们能尽可能多的使用高速设备,而尽可能少的去访问低速设备成为提高程序性能的关键原创 2020-11-13 02:23:14 · 359 阅读 · 0 评论 -
Linux标准IO①:流与缓冲
【关于标准IO和文件IO】文件IO指的是操作系统提供的系统调用,包括open write read等sys call 应用程序调用它们时将陷入内核,意味着上下文的切换,因此它们的开销是较大的。 标准IO是对文件IO的封装,核心是实现一个位于用户区的缓冲区,IO操作首先在缓冲区中进行,减少了sys call,带来了性能的提升,同时方便用户处理。用户读取一个普通的磁盘文件,需要进行多次拷贝操作:首先发起标准IO操作=》标准IO发现自身缓冲区没有数据=》发起sys call执行文件IO=》内核加载原创 2020-11-10 01:10:55 · 246 阅读 · 0 评论 -
GDB调试①:断点设置与分步执行
gdb是符合gpl自由公共许可证的gun体系下调试工具,功能简洁易用,可以随心所欲的查看程序运行过程中的信息。一个app程序:#include<iostream>using namespace std;int func(int a,int b){ return a+b;}int main(){ int* arr=new int[3]; arr[0]=1; arr[1]=2; arr[2]=func(arr[0],arr[1]);原创 2020-11-07 02:46:41 · 6625 阅读 · 0 评论 -
Linux文件系统①:硬链接与软链接
磁盘中的数据总是以固定大小的块来进行存取,即4096字节4k ,一个磁盘可以划分为多个分区,每个分区包含一个文件系统,而i节点是固定长度的记录项,包含了文件的大部分信息:磁盘中的文件以数据块的形式进行存放,而i-node则是对文件的描述:i-node:用于存储文件所有者、长度、创建时间等文件元数据的结构,存在于磁盘中的inode区域一个典型的i 节点包含以下相关信息:字段 含义 Size 表明文件的大小 Uid 表明文件拥有者的User ID ...原创 2020-10-27 13:51:50 · 255 阅读 · 0 评论 -
pthread②:双线程交替打印
两个线程交替打印0=>100 。【错误思路】采取一个互斥锁,一个全局变量flag,线程申请互斥锁:若线程1申请成功,且当前flag=true 线程1打印偶数 若线程2申请成功,且当前flag=false 线程2打印奇数static bool flag=true;void* func1(void*){ for(int i=0;i<50;i++) { pthread_mutex_lock(&mutex); cout..原创 2020-10-26 10:54:16 · 634 阅读 · 0 评论 -
Linux控制流④:信号控制
异常控制流发生在程序控制权转移到其它位置时,异常控制可能发出自硬件层面(IO设备中断)、内核层面(系统调用)、以及软件层面(即Linux信号) 允许进程和内核中断其它进程。它是一种更高级的控制。一个信号即一条简短的消息,它通知进程系统发生了某种类型的事件。每种信号对应于某种特定事件的发生,典型地,它们通常是某种硬件设备发出,(在中断中,将会发出硬件中断信号,处理器切换到中断上下文执行),而这一切对于应用程序是未知,Linux信号提供这样一类实现:通知用户进程发生了这些事件。序号 名称原创 2020-10-20 02:17:56 · 209 阅读 · 0 评论 -
Linux控制流③:fork和execve
Unix中提供许多从C程序中操作进程的系统调用,其中最重要的两个是fork和execve。它们也是Linux下实现并发编程的关键。【fork】pid_t fork(void);该系统调用创建一个几乎和父进程完全一样的子进程。子进程得到与父进程虚拟地址空间的一个副本,即包含的代码段、数据段、运行时堆、用户栈。另外,子进程还获得父进程打开的文件描述符。对应其在内核中的进程描述符task_struct 不完全相同。 两者最大的区别在于:PID即进程标识符不同。fork函数的主要特点包括:.原创 2020-10-20 01:07:20 · 2778 阅读 · 0 评论 -
Linux控制流②:处理器模式与上下文切换
【内核模式与用户模式】操作系统为进程提供两个抽象:处理器抽象与内存抽象,使得应用程序进程仿佛拥有全部的处理器时间,和一个私有地址空间。处理器需要提供一种机制,限制一个应用可以执行的指令以及可以访问的地址空间。处理器通过一个控制寄存器的模式位来控制当前执行进程的指令执行权限。设置了模式位:进程处于内核模式,可以执行处理器指令集的全部指令以及访问任何一个内存位置。未设置模式位:进程处于用户模式,用户模式只能执行处理器指令集中的部分指令,即不允许执行特权指令:停止处理器(关机)、.原创 2020-10-19 00:36:58 · 257 阅读 · 0 评论 -
Linux控制流①:异常与异常处理
计算机在运行过程中,其程序计数器PC的数值从时间轴上看是一个序列:a0 a1 a2 a3 a4 a5 a6 .... 其中第k个对应于指令Ik的地址,每次从k到k+1 的过程发生控制转移。而这样的序列称为控制流。如果k到k+1在地址上不连续,那么发生控制突变,通常由于跳转、调用、返回引起。计算机执行过程中,可能发生三大类型的控制突变,即异常控制流:硬件层面,硬件检查到事件发生,触发控制转移到异常处理程序 系统层面,内核通过上下文切换context_switch将控制转移到另一个用原创 2020-10-18 23:39:22 · 392 阅读 · 0 评论 -
Linux进程管理①:进程描述符task_struct
进程是程序在数据集合上的运行过程,是处于执行期的程序。而线程被认为是进程中的具体执行流,共享进程的地址空间和打开的文件描述符。对于进程,核心是两个虚拟机制:虚拟处理器:内核为进程提供这样一种抽象,每个进程独享处理器。 虚拟内存:内核为每个进程提供私有独立的地址空间,进程仿佛拥有独占的内存资源。进程也称为任务,Linux内核通常将进程描述为任务。【进程描述符】内核将描述进程的数据结构维护在一个任务队列中,即:task_list 其实现为双向链表。而每一项元素为:进程描述符:ta...原创 2020-10-17 02:32:15 · 448 阅读 · 0 评论 -
Linux系统级IO②:RIO-带缓冲区IO实现
UNXI系统级的IO函数,在某些情况下,传送的字节数比用户要求的少,会出现不足值(short count)主要原因为:①读取时遇到EOF:文件的大小不足以填充read需要读取的字节数,那么返回不足值0表示提前遇到EOF ②从终端读取文本行:read函数每次传送一个文本行,返回的不足值表示文本行的大小 ③读写网络SOCKET:由于网络延迟等原因,对Linux套接字执行read可能返回不足值(数据还没有接受完)一种策略是反复调用read函数,直到将所需要的字节全部读取完毕。另一种思路采取缓冲区方式:原创 2020-10-16 12:34:25 · 1045 阅读 · 1 评论 -
Linux系统级IO①:文件描述符表与IO重定向
输入输出是主存和外部设备(磁盘、终端、网络)之间数据传送的过程:输入:从IO设备传送数据到内存输出:从内存传送数据到IO设备高级语言都提供处理IO的高级别工具:ANSI C提供的标准IO库,printf scanf带有缓冲区的格式化函数,C++通过重载<< >>提供带缓冲区的格式化函数。而在一个Unix系统中,底层的系统级IO即为Unix IO ,C中的标准IO是对它的封装和完善,同时诸如RIO等封装库也基于此:关于IO,UNIX设计哲学为:一切I.原创 2020-10-15 20:40:37 · 287 阅读 · 0 评论 -
Linux线程间同步③:自旋锁Spinlock
对于Mutex互斥锁,其同一时间只能被一个线程所占有,其它申请该锁的线程会进入阻塞休眠态,让出CPU时间片。其一般使用在临界区逻辑较长的程序中,使得多线程互斥的访问临界资源。而Linux中引入自旋锁主要是解决多处理器对内核数据结构的互斥访问。确保其访问的原子性,基本流程为:锁定=》操作=》解锁自旋锁其功能和互斥锁类似,目的是保护一小段临界区的原子性,其本质为一个原子变量atomic,主要包含两种状态:locked unlocked当一个任务希望执行访问临界资源的临界区时,需要检查这个原创 2020-10-14 14:24:37 · 329 阅读 · 0 评论 -
Linux线程间同步②:条件变量Condtion
互斥锁提供了一种线程互斥访问临界资源的方式,但其存在一个问题:调用pthread_mutex_lock 线程在没有申请到锁时将一直阻塞等待。调用pthread_mutex_trtlock 线程虽然无需一直等待,但可能需要不停的检查锁是否可用而条件变量提供了一种阻塞=》唤醒方式,即线程A发现条件不成立时,执行wait_condition进入block,加入到条件阻塞队列, 而其它线程B在修改了条件后,发出一个signal信号唤醒阻塞队列,使线程A继续执行。这样一来避免了线程无目的的等原创 2020-10-14 01:09:40 · 248 阅读 · 0 评论 -
Linux线程间同步①:互斥锁Mutex
进程间通信往往意味着系统调用,内核态,用户态的切换,其代价是不容忽视的。而线程是进程中的具体执行流,一个进程中多个线程共享进程的资源,包含进程的虚拟地址空间,进程打开的文件描述符,进程组ID等。而线程间的通信和同步由于处于同一地址空间下,也更加轻易和轻量级。多线程之间访问共享变量时,这些共享变量若每次只能被一个线程进行访问,称为临界资源。而对临界资源的访问在多线程环境下,如果不加以控制,很容易出现不一致性。最常见的便是多线程售票问题。由于每个线程在执行售票(取得票数=》扣款=》票数i--=》写回原创 2020-10-13 22:11:15 · 376 阅读 · 0 评论 -
Linux链接②:符号解析与重定位
【符号解析】:将每个符号引用与输入的可重定位目标文件的符号表中的一个确切符号定义关联起来对于那些符号引用与符号定义在同一个模块(文件)的情况,符号可以直接简单的解析。对于那些符号引用不在本模块(文件)的情况,问题变得复杂。在编译器单独编译一份编代码时,每当遇到一个不在本模块中定义的函数或者全局变量,会假设符号在其它位置定义。所以能够单独通过编译。同时生成一个链接器符号表条目。如果链接器在所有输入模块找不到这个被引用符号的定义,那么输出错误信息。 如果能够在其它模块找到这个被引用符号的原创 2020-10-09 01:37:42 · 650 阅读 · 0 评论 -
Linux进程间通信⑤:IPC-消息队列
Linux System V IPC三大类通信方式:共享内存、信号量、消息队列其基于统一的ftok获取IPC资源的key 并执行相应的系统调用semget shmget创建相应的IPC资源。消息队列,顾名思义,进程可以向消息队列中写入消息,而其它进程可以从消息队列中读取消息。消息队列通过执行系统调用,由内核创建和维护,并向用户进程提供读写窗口,从而实现进程间通信。其关键函数如下:int msgget(key_t key,int msgflag)key:由ftok获取的IPC资...原创 2020-10-13 01:45:51 · 312 阅读 · 0 评论 -
Linux进程间通信④:IPC-信号量
信号量是操作系统中线程、进程间访问临界资源的同步方式。当信号量>0时,表示当前临界资源的数量。 当信号量=0时,表示当前没有可用的临界资源。 当信号量<0时,表示当前等待该临界资源的进程数量。其有两个关键操作:P:申请临界资源,申请成功那么信号量-1V:释放临界资源,释放成功那么信号量+1System V IPC资源包含共享内存、消息队列、以及信号量。其关键函数如下:int semget(key_t key,int num_sems,int sem_flags).原创 2020-10-13 00:39:03 · 399 阅读 · 0 评论 -
Linux进程间通信③:IPC-共享内存
共享内存是基于虚拟内存的机制,在进程的地址空间中,共享区域的虚拟页通过内核中的页表映射到实际的物理页中,当多个进程都映射到同一块物理页,那么它们访问的就是同一片物理内存,即共享内存。此时基于同一片内存,进程间进行信息传输的速度将非常快,每个进程相当于访问自己地址空间内的内存数据。关键函数:key_t ftok(const char* pathname,int proj_id)该函数通过将一个Linux目录名和一个项目ID生成唯一的一个IPC键值。目录必须存在,并且目录不变时..原创 2020-10-12 21:34:48 · 296 阅读 · 0 评论 -
虚拟内存②:Linux虚拟内存系统
Linux系统为每一个进程维护一个单独的地址空间,包含了进程的内存分区即:代码段、数据、运行时堆栈,共享库等部分。除了进程私有的虚拟地址空间外,内核虚拟内存地址包含内核的代码和数据,所有进程的这部分区域被映射到同一个物理页面。另外,与每一个进程相关的进程信息,例如进程的页表,mm内存映射结构等也存放在内核地址空间中,由内核进行维护。Linux将这些不同区域称为段(segement)一个段包含若干的个连续的虚拟页。不同的区域之间在地址空间中不一定连续。例如:Linux中进程的s.原创 2020-10-12 00:37:53 · 428 阅读 · 1 评论 -
Linux进程间通信②:有名管道FIFO
常规的匿名管道通过pipe创建一片内存缓冲区,并对外提供两个文件描述符,用于只读或者只写操作。但其使用范围很小,只能用于父、子进程间的通信。因此Linux还提供有名管道的支持。管道的本质是一片可以读写的缓冲区域,Linux将其描述为文件(UNIX思想:一切IO皆是文件) 对于有名管道,其主要特点是:存在于文件系统中,包含文件名,管道文件被组织成树状结构 两个进程之间无需有联系,可以通过管道进行通信 对有名管道的操作和文件操作类似,支持读,写【有名管道的创建】mkfifo(const.原创 2020-10-11 12:13:13 · 345 阅读 · 0 评论 -
Linux进程间通信①:匿名管道PIPE
对于多线程,其共享同一进程下进程的虚拟地址空间。包括运行时堆区域,进程的.text代码段,.rodata只读数据段,以及.data全局数据段,以及共享库。另外,进程是操作系统进行资源分配的基本单位,多线程还可以共享进程的打开文件(FD),进程的Pid等。由于处于同一个地址空间,线程之间通信可以方便自然的进行。而进程与进程之间由于处于不同的虚拟地址空间,它们之间的通信采取其它的机制。早期的Linux对进程间通信支持的良好,以至于在很长一段时间内,Linux不支持多线程。管道是一种特殊的文件,.原创 2020-10-11 11:02:51 · 275 阅读 · 0 评论 -
Linux链接③:加载与执行
链接器将多个可重定位目标文件合并成可执行目标文件,可执行目标文件格式同可重定位目标文件的格式大致相似。ELF头部描述文件的总体信息。它还包括程序的入口点(entry point) 。它指向程序执行时第一条指令的地址。.text .data .rodata各部分节都被重定位到运行时内存地址。其中包含一个 .init节 其定义了一个小函数,程序的初始化代码会将其调用。另外,可执行文件是完全链接的(符号均已经被重定位),所以它不需要.rel 节。objdump -h main 通过objdump查看原创 2020-10-09 20:47:31 · 321 阅读 · 0 评论 -
Linux链接①:目标文件格式
链接:将各种代码段和数据段收集组合成为一个单一文件的过程。链接的执行过程可以发生在三种时期:编译期:源代码翻译成机器代码的过程中。 加载期:程序被内核加载器加载到内存时。 运行期:应用程序来控制执行。链接器的出现使得构建大型软件系统成为可能,因为它使得各个模块可以单独完成编译。当需要改进模块时,单独的修改相应的模块并编译,通过链接器重新链接生成新版本的软件系统。根据链接的发生时期不同分为以下三类:传统静态链接 加载时共享库动态链接 运行时共享库动态链接一个典型的链接过程:原创 2020-10-09 00:44:35 · 402 阅读 · 0 评论 -
Linux IO同步复用②
IO复用通过时分复用的形式,多个socket连接使用同一个IO线程,IO线程通过系统调用的方式获知被监视的文件标识符列表中就绪的文件,执行IO操作。这里的同步指代在执行IO操作时,会等待动作完成再继续执行,复用是采取一个线程完成对多个IO流的处理。Linux中poll方式是对select的改进,select存在一个文件描述符监视数量上限,即1024 而改进的poll去除了该上限。poll方式维护一个监听数组,数组中的元素是一个结构体,结构体形式如下:struct pollfd{ in.原创 2020-10-06 13:48:26 · 177 阅读 · 0 评论 -
Linux IO同步复用①
关于同步与异步:同步:调用者在执行一个调用时,一直等待调用完成返回后才进行后续操作。异步:调用者执行一个调用时,立即返回,继续进行后续操作而不关心调用是否完成。异步与同步是对通信机制的描述,而阻塞、非阻塞关心的是调用者的状态:阻塞:当执行一个调用时,调用者线程一直被挂起(CPU时间片切换给其它线程),直到调用完成返回。非阻塞:当执行一个调用时,调用者线程仍然活跃。值得注意的是同步调用过程,在等待过程线程可能并没有挂起,而只是一直等待(占用着资源)。IO多路复用:是一种..原创 2020-10-06 01:48:09 · 333 阅读 · 0 评论 -
实现自己的静态链接库与动态链接库
静态链接库是指在源代码中调用库中的函数,再被编译为.o目标文件后,再链接上库文件,形成可执行程序。库文件中存放多个.o目标文件,它们存放着各个函数的定义,最终被一起链接进可执行程序。那么在运行期之前,可执行程序中就包含所有程序运行的条件,也就是所谓的静态链接。首先,新建两个.cpp文件 add.cpp sub.cpp 它们中都定义了两个简单的函数g++ -c add.cpp sub.cpp生成如下2个对象文件 add.o sub.o进一步,通过nm命令查看该.o文件...原创 2020-09-30 00:10:57 · 322 阅读 · 2 评论 -
pthread 多线程
多线程程序指的是在同一个程序中多个执行流并发执行,它们共享进程的同一个地址空间,分别完成相应的任务,并通过共享地址空间等方式完成线程间通信,CPU按照时间片轮转等方式对线程进行切换和调度。通常而言,线程共享的进程资源包括:线程之间共享内存地址空间中的堆区,也就是动态创建的区域 同时每个线程有自己的堆栈区,以进行函数调用和返回,局部变量的创建与销毁。 在进行线程切换时,每个线程依据相应的寄存器组保护现场和还原现场 线程共享进程打开的文件描述符(FD : linux中认为一切IO设备可采取文件描述原创 2020-09-27 19:00:06 · 925 阅读 · 0 评论