279 words
命名管道之前我们使用的都是匿名管道,命名管道与之不同的就是他拥有实体文件,文件类型为p,而且他的文件大小永远为0 这时因为打开文件的同时也打开了缓冲区 当两个进程分别打开管道时,如果分别分配两个缓冲区,连接着管道文件本体,这样实在低效 不如直接两个进程连接同一个缓冲区 命名管道也称之为fifo,先进先出,也可以理解其是单向的 创建命名管道命令行1mkfifo fifo 函数1mkfifo("./testfifo",0666); 第一个参数是管道文件,第二个参数是权限,和open系统调用一样 他的返回值是int类型,返回值为-1时表示出创建管道失败 创建管道文件完成之后的任务就简单了 只用像正常读写文件的操作进行读写就可以了 可以使用系统调用接口,也可以使用C语言接口都是没问题的
3.5k words
池化技术池化技术其实是分治思想的一个体现,在生活中也有很多例子 例如,河水的水资源非常丰富,但是要多次从河水中取水使用是比较繁琐且低效的,尤其是当家离河流较远的时候(消耗较大),这时候我们就可以每次取一大缸水,需要使用的时候直接取水使用就可以了 进程池也是类似的思想,因为每一次fork创建子进程都需要进行系统调用,也需要消耗一定的资源,因此我们可以一次申请一定数量的进程PCB,分别分配对应的任务给他们就可以了 这实际上就是一种多进程并发运行的思想,我们可以用父进程来进行子进程的管理与任务分配、任务验收,然后让这些兄弟进程来运行不同的任务,这其中传递信息就需要用到我们前一篇所学的匿名管道 但是在这里我们先不具体分配,只是体会其中的思想即可 进程池进程池原理画成示意图就是这样的 蓝色是每一次我们fork子进程和pipe管道之后,需要关闭的接口,因为每一次的读接口都是3,所以从4、5、6以后的分别对应的就是不同的子进程的写管道 这里其实还有一个隐藏起来的bug,就是在第二个子进程以及之后的子进程fork的时候,实际上他拷贝的是父进程的文件描述符表,因此他也存在一个接口指向之前申请的写...
1.2k words
进程间通信进程设计的特点之一就是独立性,要避免其他东西影响自身的数据 但有时候我们需要共享数据或者传递信息,传统的父子进程也只能父进程传递给子进程信息 因此进程间通信还是很必要的,除此之外网络通信中所说的进程间通信本质上也是两个进程进行通信,只不过信息传递经过了繁杂的计算机网络 进程间通信有很多类型,但是利用管道进行进程间通信对我们了解底层原理还是很有帮助的,因此我们也从管道开始介绍 管道在我们学习Linux指令的时候,有一个字符是|,用于将前一个指令的输出传递给下一个指令作为输入 通过这么久的学习,我们可以大概猜测出这个管道的原理是什么样的 两个指令本质上就是两个进程,利用管道进行通信,将两个管道连接起来 如何控制这两个进程的输入输出呢,其实就用到了之前的重定向功能 头一个指令的输出进行重定向,后一个指令的输入重定向就可以实现这样的功能了 再深入一点,管道的本质其实就是一个被打开的文件,但同时能被两个进程访问,而且只能一个进程写,另一个进程读 匿名管道匿名管道通常用于父子进程的通信 父进程使用pipe函数创建管道 这个函数的参数是一个描述符数组,下标0表示读,下标1表示写...
1.3k words
什么是文件系统我们之前所说的文件读写都是通过进程对已经打开的文件进行操作,也就是对操作系统对文件所创建的结构体进行操作 那么对于磁盘中没有打开的文件是如何进行管理的 磁盘的物理结构这里我们主要讨论机械磁盘而非固态磁盘,因为机械磁盘的价格较低,而且学习之后也能更好的理解整个系统 这是机械硬盘内部的样子,有点像光盘的样子,不同的是光盘只能读,机械磁盘可以读写,而且机械磁盘是一摞的,利用这个磁头来感应出来0和1 绕着这个转轴,就是圆心,有不同的半径的圆,我们称之为磁道,同一个磁道所组成的称为柱面,而为了同时读取数据,按照不同的圆心角划分成了不同的扇区 我们可以把某一个磁道的扇区单独取出来,看成一个数组,这样就能把文件系统划分成众多这样的数组,再将其组织起来即可 这样对磁盘问题就变成了对数组的问题,存储数据到磁盘就变成了存数据到数组,从磁盘取数据就是找到数组中的位置,对磁盘的管理也就成了对数组的管理 这样一个扇区的大小是512字节,接下来就是对扇区如何进行划分管理了 扇区中的块组直接管理512字节还是过于麻烦,我们仍然需要对其进行设计才能很好的管理其中的内容 一个扇区会分成若干个这...
863 words
重定向我们在学习Linux的基本内容时候,知道>> >都可以用来表示重定向,那么重定向的本质是什么呢,其实就是更改了标号为1的文件描述符 1表示标准输出,那么我们也就可以手动实现输出重定向,将标准输出更改为我们指定的文件 1234567891011121314 1 #include<unistd.h> 2 #include<sys/types.h> 3 #include<sys/stat.h> 4 #include<fcntl.h> 5 #include<stdio.h> 6 7 int main() 8 { 9 close(1);10 int fd = open("log.txt",O_WRONLY|O_CREAT|O_TRUNC,0666);11 printf("关闭1之后新建文件标识符为%d\n",fd);12 fprintf(stdout,"输出到更改后的标准输出\n"); 13 ...
1.1k words
在Linux系统下有句名言是,Linux中一切皆文件 C语言中的文件接口在C语言中有三个数据流,分别是stdin、stdout、stderr,这三个标准文件是交给程序员来输入输出的 可以从键盘读入,显示器输出,也可以输出到文件中,那么其实在操作系统内部,他是把显示器、键盘等外设也看作是文件,向显示器输出和向磁盘文件中输出写入是没有本质区别的 C语言打开文件的函数是fopen,读取是fread、fscanf、fgets,写入是fwrite、fprintf、fputs,和基础的scanf、gets使用都是一致的,只需要在末尾加上写入的文件指针即可 fopen的返回值和三个数据流都是文件指针类型的,是FILE* 操作文件的系统调用每一种语言都有各自不同的文件操作函数,但不管语言如何改变,想要对文件进行读写都需要让操作系统帮忙,使用系统调用才能对文件进行操作 操作系统有四个系统调用 open、close、write、read open 我们主要看第一个定义,他的返回值是文件描述符fd,第一个参数是打开文件的路径,flags是你想要打开文件的方式 因为文件的打开方式比较繁多,不能每一个都设...
1.5k words
在学习进程的时候,我们想fork一个子进程,然后就可以给他布置任务了 但是如果我们分成两个人开发,父子进程分别负责不同的任务,等待开发完成之后除了合并项目或者复制粘贴还有更好的办法吗 其实是有的,当子进程被创建后不想执行父进程代码时,就需要用到程序替换 主要是exec系列函数的用法 exec系列函数 这里一共有六个函数,但是是同一个系列的,也有一定的规律,如果他们替换失败了,返回值都是-1 execl这是里面最简单的函数,他的函数有两个,第一个是执行的程序路径,之后的是参数包,表示如何执行该程序 可以理解为前一个是环境变量,后一个是程序指令,只不过按单词分开,具体使用是这样的 例如 12345678910111213#include<stdio.h>#include<unistd.h>int main() { printf("程序替换\n"); int n = execl("/usr/bin/ls","ls","-a","-...
935 words
进程等待进程等待的过程其实是父进程等待子进程死亡的过程 进程等待的必要性如果子进程退出,父进程不进行处理,子进程会变成僵尸进程,有内存泄漏的风险 僵尸进程只有父进程有权处理,其他指令对其都没有效果了 父进程创建子进程是为了完成某项任务,当子进程结束后,父进程有必要了解任务完成的如何 父进程需要对子进程进行回收 进程等待的方法waitpid系统调用的返回值是pid_t,如果等待成功则返回进程pid,失败则返回-1 这个函数有三个参数,第一个参数是pid_t pid,表示需要等待的进程id,输入-1表示等待任一子进程结束 第二个参数是int* stat_loc,这是一个输出型参数,采用指针的方法获取子进程退出状态,如果我们不关心这个状态直接传入NULL即可 第三个参数是int options,默认为0,代表阻塞等待,也有非阻塞等待的情况 还有一个wait的系统调用,只有第二个参数,就相当于waitpid的默认使用情况 12345678910111213141516171819202122#include<sys/wait.h>#include<stdlib.h>...