还在排版中
对文中很多定义不是很肯定,希望能有人指正。
提问
问题1.为什么复制一个大文件比复制很多小的文件快。
问题2.从服务器上复制文件使用多线程还是多进程。
问题3.那么严格意义上线程除了TLS以外没有私有变量?只要获得了指针,便可以对其他线程的数据进行修改。
问题4.内核空间和用户空间都是虚拟内存的一部分?
问题5.对于高并发的网络请求,多进程多线程可能都不能满足?对于c语言来说,又是什么情况?
问题5.各种IPC使用场景,虽然搜索了一些资料,但觉得十分片面,理解不深。
问题6.使用socket麻烦的地方,头,协议,封装,配置成本?
问题7.零拷贝是什么
问题8.冲洗和关闭?
问题9.默认I/O流
问题10.signal和sigaction的区别
其他的也希望老师能过目一下,确认下我的理解没有错误
CPU密集型和IO密集型
由于python GILd的存在,python多线程并不是并行而是并发,也就导致了CPU密集型任务效率的下降
IO密集型因为等待而挂起的时间很长,所以多线程也适用,并且创建线程,上下文切换消耗的资源都比进程小,所以速度更快。
因此,对于python,cpu密集型使用多进程,而IO密集型使用多线程
对于高并发的网络请求,多进程多线程可能都不能满足?对于c语言来说,又是什么情况?
对于一个聊天室应用,十个通信设备各开一个线程,对cpu负担很大,这时候应用的就是IO多路复用select,poll,epoll
顺带一提,对于cpu读写的负担使用的是缓存和缓冲。
暂未了解 并发 nginx,apache,tomcat,
进程的切换=进程中线程的切换
暂未理解使用socket麻烦的地方,头,协议,封装,配置成本?
暂未了解IPC,RPC,API网关
第一章
文件和目录的区别?
在linux中,都是以文件描述的,他们的文件类型不同。
目录文件存储了目录下所有文件名和inode的映射关系。
把文件rm掉会发生什么?
1)使用unlink减少链接数量,
2)如果链接数为0释放inode,则数据块放到可用空间列表中;
3)删除目录中的目录项
https://blog.csdn.net/weixin_...
为什么同一个文件系统移动文件很快?
因为只删除了目录中原位置的对应关系,在移动后的位置加上了新的对应关系,没有对数据进行写处理。
不同文件系统使用的是rm+cp
格式化?
inode-table也是需要占用存储空间的。
第三章
缓冲和缓存
见我的文章 buffer and cache
https://segmentfault.com/a/11...
第七章
已经忘记 fork和vfork
暂未理解 如何保存密码,将密码写入环境变量中
第十章
kill -9 init会发生什么?
The only signals that can be sent to process ID 1, the init process, are those for which init has explicitly installed signal handlers. This is done to assure the system is not brought down accidentally.
根据上文,什么都不会发生,因为init没有对SIGTERM建立signal handler?
https://unix.stackexchange.co...
第十一章?
cpu上下文切换分为进程上下文切换,线程上下文切换,中断上下文切换
进程和线程的异同点?
(1)
线程是调度的基本单位,而进程则是资源拥有的基本单位
进程时系统资源分配的最小单位
线程时cpu操作和调度的最小单位,本质是一组寄存器的状态,是操作系统对寄存器状态的抽象
e.g. 进程就是一个人,线程就是这个人收到的一件事情,对于很多事情,一个人可以做多件事情,或者可以喊很多人每个人做一件事。
(2)
上下文切换成本 进程远大于线程
进程的上下文不仅包括了虚拟内存、栈、全局变量等用户空间的资源,还包括了内核堆栈、寄存器等内核空间的状态。
线程上下文切换线程局部存储 (TLS) ,栈和寄存器等
这两种上下文切换的处理都是通过操作系统内核来完成的。
内核的这种切换过程伴随的最显著的性能损耗是将寄存器中的内容切换出。
(3)
进程中的线程共享地址空间,进程间的通信的代价远大于线程间的通信
得设立管道,共享队列,信号,信号量,socket
(4)
线程的创建成本远远低于进程,因为线程中包含的数据量少于进程,线程只需要执行相关的数据即可,如,pc,寄存器,栈,执行状态
第十一章
线程之间独有的资源有
https://cloud.tencent.com/dev...
栈区
同时函数运行时需要额外的寄存器来保存一些信息,像部分局部变量之类,这些寄存器也是线程私有的,一个线程不可能访问到另一个线程的这类寄存器信息。
所属线程的栈区、程序计数器、栈指针以及函数运行使用的寄存器是线程私有的。这些信息有一个统一的名字,就是线程上下文,thread context。
那么严格意义上线程除了TLS以外没有私有变量?只要获得了指针,便可以对其他线程的数据进行修改。
TLS -> Thread Local Storge?
存放在该区域中的变量是全局变量,所有线程都可以访问
他是全局的,但是每个线程在访问的时候都会存储一份成为自己的局部变量,修改就不会相互影响了
虽然看上去所有线程访问的都是同一个变量,但该全局变量独属于一个线程,一个线程对此变量的修改对其他线程不可见。
实现原理类似有一个全局的词典,词典的key是线程id,value就是共享的全局变量的副本。
http://blog.hacksmeta.com/201...
线程共享的资源
代码区 编译后的代码
数据区 全局变量,静态变量。
堆区 C/C++中用malloc或者new出来的数据就存放在这个区域,只要知道指针,任何一个线程都可以访问指针指向的数据,因此堆区也是线程共享的属于进程的资源。
栈区 如果一个线程能拿到来自另一个线程栈帧上的指针,那么该线程就可以改变另一个线程的栈区,也就是说这些线程可以任意修改本属于另一个线程栈区中的变量。
动态链接库 动态链接的部分生成的库就是我们熟悉的动态链接库,在Windows下是以DLL结尾的文件,在Linux下是以so结尾的文件。
文件
如果程序在运行过程中打开了一些文件,那么进程地址空间中还保存有打开的文件信息,进程打开的文件也可以被所有的线程使用,这也属于线程间的共享资源。
忘记问题是什么 cpu密集型中降低cpu使用率?
①增加cpu
②降低系统进程,线程数
锁的使用场景
见我的文章UNIX环境高级编程第十一章遗留问题笔记
https://segmentfault.com/a/11...
第十四章
阻塞,非阻塞
阻塞和非阻塞关注的是程序在等待调用结果(消息,返回值)时的状态.
阻塞调用是指调用结果返回之前,当前线程会被挂起。调用线程只有在得到结果之后才会返回。
非阻塞调用指在不能立刻得到结果之前,该调用不会阻塞当前线程。程序定时?查看调用是否完成。
同步和异步
同步与异步同步和异步关注的是消息通信机制 (synchronous communication/ asynchronous communication).
所谓同步,就是在发出一个调用时,在没有得到结果之前,该调用就不返回。但是一旦调用返回,就得到返回值了。换句话说,就是由调用者主动等待这个调用的结果。而异步则是相反,调用在发出之后,这个调用就直接返回了,所以没有返回结果。换句话说,当一个异步过程调用发出后,调用者不会立刻得到结果。而是在调用发出后,被调用者通过状态、通知来通知调用者,或通过回调函数处理这个调用。
第十五章
https://www.jianshu.com/p/498...
进程间通信有什么类型?他们的应用场景分别是什么?
内核空间和用户空间都是虚拟内存的一部分?
消息队列和管道基本上都是4次拷贝,而共享内存(mmap, shmget)只有两次。
一、管道
它是半双工的(即数据只能在一个方向上流动),具有固定的读端和写端。
它只能用于具有亲缘关系的进程之间的通信(也是父子进程或者兄弟进程之间)。
它可以看成是一种特殊的文件,对于它的读写也可以使用普通的read、write 等函数。但是它不是普通的文件,并不属于其他任何文件系统,并且只存在于内存中。
应用场景?
二、FIFO
FIFO,也称为命名管道,它是一种文件类型。
FIFO可以在无关的进程之间交换数据,与无名管道不同。
FIFO有路径名与之相关联,它以一种特殊设备文件形式存在于文件系统中。
应用场景?
三、消息队列
消息队列,是消息的链接表,存放在内核中。一个消息队列由一个标识符(即队列ID)来标识。
消息队列是面向记录的,其中的消息具有特定的格式以及特定的优先级。
消息队列独立于发送与接收进程。进程终止时,消息队列及其内容并不会被删除。
消息队列可以实现消息的随机查询,消息不一定要以先进先出的次序读取,也可以按消息的类型读取。
应用场景
优点上面已经说了,就是在特殊场景下有其对应的好处,解耦、异步、削峰
系统可用性降低:系统引入的外部依赖越多,越容易挂掉,本来你就是A系统调用BCD三个系统的接口就好了,人ABCD四个系统好好的,没啥问题,你偏加个MQ进来,万一MQ挂了咋整?MQ挂了,整套系统崩溃了,你不就完了么。
系统复杂性提高:硬生生加个MQ进来,你怎么保证消息没有重复消费?怎么处理消息丢失的情况?怎么保证消息传递的顺序性?头大头大,问题一大堆,痛苦不已
一致性问题:A系统处理完了直接返回成功了,人都以为你这个请求就成功了;但是问题是,要是BCD三个系统那里,BD两个系统写库成功了,结果C系统写库失败了,咋整?你这数据就不一致了。
https://zhuanlan.zhihu.com/p/...
消息队列和管道基本上都是4次拷贝,而共享内存(mmap, shmget)只有两次。
第一步读磁盘文件是要经过一次系统调用的,它首先将文件内容从磁盘拷贝到内核空间的一个缓冲区,然后再将这些数据拷贝到用户空间,实际上是两次数据拷贝。第三步回写也一样也要经过两次数据拷贝。
4次:1,write()输入从磁盘到A内核空间。2,写进B用户空间。3,B调用read()读入内核空间。4,从内核空间中放入磁盘.
而内存映射文件是操作系统的提供的一种机制,可以减少这种不必要的数据拷贝,从而提高效率。它由mmap()将文件直接映射到用户空间,mmap()并没有进行数据拷贝,真正的数据拷贝是在缺页中断处理时进行的,由于mmap()将文件直接映射到用户空间,所以中断处理函数根据这个映射关系,直接将文件从硬盘拷贝到用户空间,所以只进行了一次数据拷贝 ,比read进行两次数据拷贝要好上一倍,因此,内存映射的效率要比read/write效率高。
2次:1,输入到用户空间。 2,用户空间到输出。
零拷贝?
消息队列和管道都是内核对象,所执行的操作也都是系统调用,而这些数据最终是要存储在内存中执行的。因此不可避免的要经过4次数据的拷贝。但是共享内存不同,当执行mmap或者shmget时,会在内存中开辟空间,然后再将这块空间映射到用户进程的虚拟地址空间中,即返回值为一个指向一个内存地址的指针。当用户使用这个指针时,例如赋值操作,会引起一个从虚拟地址到物理地址的转化,会将数据直接写入对应的物理内存中,省去了拷贝到内核中的过程。当读取数据时,也是类似的过程,因此总共有两次数据拷贝。
优点:
A. 我们可以通过发送消息来几乎完全避免命名管道的同步和阻塞问题。
B. 我们可以用一些方法来提前查看紧急消息。
缺点:
A. 与管道一样,每个数据块有一个最大长度的限制。
B. 系统中所有队列所包含的全部数据块的总长度也有一个上限。
四、信号量
信号量(semaphore)与已经介绍过的 IPC 结构不同,它是一个计数器。信号量用于实现进程间的互斥与同步,而不是用于存储进程间通信数据。
信号量用于进程间同步,若要在进程间传递数据需要结合共享内存。
信号量基于操作系统的 PV 操作,程序对信号量的操作都是原子操作。
每次对信号量的 PV 操作不仅限于对信号量值加 1 或减 1,而且可以加减任意正整数。
支持信号量组。
信号量的双用途:互斥 类似于mutex,但是mutex只能是加锁的人解锁 与 同步 -> 线程1和线程2 -> 线程3
五、共享内存
共享内存(Shared Memory),指两个或多个进程共享一个给定的存储区。
共享内存是最快的一种 IPC,因为进程是直接对内存进行存取。
因为多个进程可以同时操作,所以需要进行同步。
信号量+共享内存通常结合在一起使用,信号量用来同步对共享内存的访问。
使用场景
传递很大的数据
大量读同一数据的场景
六、信号
使用场景
接收进程某个时间已经发生,死亡。
七、套接字
使用场景
八、unix域套接字
使用场景
Linux-进程间通信(N): 各种IPC的使用场景
- 管道:只能用于具有亲缘关系的进行通信,使用面相对较窄,实际开发中较少使用;
- FIFO(命名管道):可以用于任意进程间的通信,对于大块数据的传输效率较高,可应用于单进程大量数据传递,和多个进程向一个进程传递数据;
- 信号:无法传递数据,而且信号的种类有限,只适用于完成一些简单的事件通知任务,如配置跟新信号通知,一个服务通过信号告知另一个服务自身状态;
- 文件锁:不能用来传递数据,用来对操作进行协调,利用文件锁实现多个进程对于某个资源的排队请求,或者多个进程对系统某个全局资源进行读写操作,可以通过文件锁实现进程间读写锁的功能;
XSI IPC:
- 共享内存:最为高效的进程间通信方式,进程可以直接读写内存,不需要任何数据拷贝,适用于多个进程共享数据,或进程间频繁的进行大量的数据交互;--建议使用mmap方式;
- 消息队列:进程间传递简单的命令和控制消息,如配置更新通知,多进程对多进程的通信等,可以简化代码逻辑;--建议使用全双工管道替代;
- 信号量:某种资源数为N,多个进程都在使用该资源,为了进行进程间的互斥,可以使用初始值为N的信号量;--建议使用记录锁替代;
套接字IPC:
- unix域套接字:某个服务与多个服务同时通信,此时需要维护多个通信通道,使用unix套接字,可以使用linux IO多路复用功能;--建议优先考虑网络套接字;
- 网络套接字:如果系统需要支持分布式部署,服务可能在同一设备或者不同设备,此时使用网络套接字比较合适,提高了扩展性;
第十六章
实现一个多客户端单服务端的聊天室应用。
见我的文章多人聊天室(多线程||epoll)
https://segmentfault.com/a/11...
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。